此代码用于智力练习,不建议使用!
如果您愿意强制BotContexts
的实现者使用特定形式,则可以在属性定义中插入一种单例模式。
考虑:
public static class Singleton {
public static T For<T>(Func<T> makeSingleton) => Singleton<T>.For(makeSingleton);
}
public static class Singleton<T> {
static Dictionary<Func<T>,T> Cache = new Dictionary<Func<T>,T>();
public static T For(Func<T> makeSingleton) {
T singleton;
if (!Cache.TryGetValue(makeSingleton,out singleton)) {
singleton = makeSingleton();
Cache[makeSingleton] = singleton;
}
return singleton;
}
}
现在您可以像这样使用它:
public class CoolContextNumberOne : BotContexts {
public override Command[] ContextSpecificCommands => Singleton.For(() => new Command[] { new CommandFoo() });
}
public class CoolContextNumberTwo : BotContexts {
public override Command[] ContextSpecificCommands => Singleton.For(() => new Command[] { new CommandFoo() });
}
每个CoolContext都会创建CommandFoo
的一个实例,而不管调用ContextSpecificCommands
的次数如何。
由于在C#中使用new
表达式将始终生成一个新对象,因此很难(不可能?)来查看您如何使代码相同并弄清楚何时生成新对象,以及何时返回现有对象(例如,Command
实际上是代理对象)。如果您不介意启用优化,则StackFrame
和GetILOffset
可能会有所帮助,但在调试模式下可能会失败。并且非常脆弱。
通过使用Singleton
和Command
可以隐藏dynamic
类型的Expando
的用法,但这似乎是一个更糟糕的主意。 / p>
,
如果不添加额外的代码,这是不可能的。
为了缓存结果,必须创建一个单独的后备字段,并且必须设置代码以使用该字段。
为了解决我的难题,我从以下位置更改了代码:
// User will override this.
public virtual Command[] ContextSpecificCommands { get; } = null;
收件人:
// User will override this.
protected virtual Command[] ContextSpecificCommands { get; } = null;
// These control the cache.
private bool HasPopulatedCommandCache = false;
private Command[] CommandCache = null;
// Things will reference this to get ahold of commands.
public Command[] Commands {
get {
if (!HasPopulatedCommandCache) {
HasPopulatedCommandCache = true;
CommandCache = ContextSpecificCommands;
}
return CommandCache;
}
}
这使代码可以满足我最初的问题中指定的所有目标。用户的类可以使用嵌入式表达式来定义其命令,而不必担心每次引用该数组时都会实例化该数组。
本文链接:https://www.f2er.com/2855750.html