C#中的吸气剂是否可以在线缓存其结果?

我一直在研究Discord机器人,而我代表服务器的抽象类之一(“ Bot Contexts”)包含以下数据。

public virtual Command[] ContextSpecificCommands { get; } = null;

在用户定义的上下文中,我希望它们可以覆盖此内容(如果具有此代码的服务器需要这样做)。但是,有一个问题是,我希望命令在上下文范围内是单例。这意味着CommandFooCoolContextNumberOne中只能存在一次,也可以在CoolContextNumberTwo中存在(作为CommandFoo的单独实例),但是单个上下文不能有两个实例其中的CommandFoo

我的问题来自吸气剂的行为。如果用户这样做...

public override Command[] ContextSpecificCommands => new Command[] {
    new CommandFoo()
};

然后,这将实例化CommandFoo 每次 ContextContextificCommands。

是否有任何方法可以确保ContextSpecificCommands被内联缓存,以便仅实例化该容器数组一次?我想避免要求用户指定一个字段,并在可能的情况下指向该字段。

xuan2901 回答:C#中的吸气剂是否可以在线缓存其结果?

此代码用于智力练习,不建议使用!

如果您愿意强制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实际上是代理对象)。如果您不介意启用优化,则StackFrameGetILOffset可能会有所帮助,但在调试模式下可能会失败。并且非常脆弱。

通过使用SingletonCommand可以隐藏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

大家都在问