单例实例不会覆盖并且为空的getter setter

时间:2019-06-07 22:21:16

标签: c#

名称仅在Main中获得一个值,而在public plname中却没有,但是我不希望人们使用Main他们像下面这样使用public plname的问题,并且覆盖也不起作用,有人可以帮我吗

public class Singleton<T> where T : new()
{
    public static readonly T Api = new T();
    protected Singleton() { Console.WriteLine("Inited"); }
}
public class SomeSingleton : Singleton<SomeSingleton>
{
    public string Name { get; set; }
    public SomeSingleton() { }
    public virtual string getPluginName() { return Name; }
}
public class plname : SomeSingleton
{
    public plname() { // this not works
        Name = "test";
    }
    public static void Main(string[] args)
    {
        Api.Name = "testing"; // this works
        Console.WriteLine(Api.getPluginName());
        Console.ReadLine();
    }
    public override string getPluginName()
    {
        return "this not works"; // this not works
    }
}  

编辑: SingletonSomeSingleton类位于.dll文件中,plname类不在dll中

我想这样使用

public class plname : SomeSingleton
{
  public plname {
     Name = "test";
  }
}

1 个答案:

答案 0 :(得分:1)

Main方法中,该方法是(间接)继承自Singleton<SomeSingleton>的类型内的方法,Api引用Singleton<SomeSingleton>.Api。这是Singleton<SomeSingleton>类型的 static 成员。因此,它明确不是既不是SomeSingleton也不是plname的新成员。

由于Api现在是Singleton<SomeSingleton>的成员,这意味着它仅被初始化一次。那时,它得到的值是new T(),其中TSomeSingleton

这意味着,除非您主动更改Api上存在的实例,否则它将始终引用相同的SomeSingleton实例,该实例将在没有任何数据(也没有名称)的情况下实例化。

这就是为什么您只做null时就得到Api.getPluginName()的原因:因为SomeSingleton的静态实例从未初始化过名称。而且由于该实例明确地不是plname的实例,所以plname的重写方法也将不适用。

因此,您将不得不忍受这样一个事实,即继承单例通常不会真正起作用,因为对原始类型的单例引用不会被神奇地更新。

假设您要编写某种插件系统,那么最好完全不必依靠单例来做到这一点。或者,也可以只用一个单例,即可在某个注册表中注册您的插件。


例如:

public interface IPlugin
{
    string Name { get; }
    void DoStuff();
}

public static class PluginRegistry
{
    private static readonly List<IPlugin> plugins = new List<IPlugin>();
    public static IEnumerable<IPlugin> GetPlugins() => plugins;
    public static void Register(IPlugin plugin) => plugins.Add(plugin);
}

// And then an example plugin implementation
public class MyPlugin : IPlugin
{
    public string Name => "My fancy plugin";
    public void DoStuff() => Console.WriteLine("My fancy plugin was called!");
}

在以下时间注册您的插件

PluginRegistry.Register(new MyPlugin());

然后您可以使用PluginRegistry访问您的插件:

foreach (var plugin in PluginRegistry.GetPlugins())
    plugin.DoStuff();

// Output:
// My fancy plugin was called!