如何在另一个类中获取单例实例

时间:2019-06-06 12:03:13

标签: c#

我想在另一个类中获取Lazy实例,问题是T类型仅在主类中设置

实例所在的第一类是这个

public class singleton<T> where T : class, new()
{
    private readonly static Lazy<T> val = new Lazy<T>(() => new T());
    public static T instance { get { return val.Value; } }

    public int UserID {get;set;} 
}  

现在我还有一个用于所有用户数据的类

public class User
{ 
    public string Name()
    {
        return data.GetUserFromID(singleton.instance.UserID)
    }
}  

单例不起作用,因为我需要参数,但是T仅在主类中

public class main : singleton<main>
{
    public main()
    {
        UserID = 5; 
    }
}

编辑

如何从另一个这样的类中的单例类获取ID
单例文件

   public class singleton<T> where T : class, new()
    {
        private readonly static Lazy<T> val = new Lazy<T>(() => new T());
        public static T instance { get { return val.Value; } }

        public int UserID {get;set;} 

        private singleton() {
         Datas.UserID = UserID;
        }    
}  

另一个文件

public class Datas {
      public static int UserID {get;set;} 
}

2 个答案:

答案 0 :(得分:0)

  

单例不起作用,因为我需要参数,但T仅在主类中

您需要做的就是从以下位置更改代码:

public class User { 
 public string Name() {
  return data.GetUserFromID(singleton.instance.UserID)
 }
}  

...以指定通用类型参数:

public class User 
{ 
    public string Name()
    {
        var m = singleton<main>.instance;
        Console.WriteLine($"Inside User.Name, m.UserId = {m.UserID}");
        return "todo";
    }
}  

这是必需的,因为您的客户代码正在直接访问通用库。如果您将其封装到工厂经理或类似人员中,则客户无需指定类型。

这里有一些测试工具

private void Run()
{
    var x = singleton<main>.instance;
    Console.WriteLine($"x.UserId = {x.UserID}");

    var y = singleton<main>.instance;
    Console.WriteLine($"y.UserId = {y.UserID}");

    x.UserID++;
    Console.WriteLine($"x.UserId = {x.UserID}");
    Console.WriteLine($"y.UserId = {y.UserID}");

    var user = new User();
    Console.WriteLine($"User.Name = {user.Name()}");

    var mp = MissPiggy.Instance;
}

将产生以下结果。请注意,更改两个不同变量的属性会如何修改相同的单例。

enter image description here

实现单例的方式也存在一些问题。单例类应具有private构造函数,并且应该是一个管理生命周期的构造函数,而不是辅助类。

例如

public sealed class MissPiggy
{
    private static Lazy<MissPiggy> _instance = new Lazy<MissPiggy>(() => new MissPiggy());

    private MissPiggy()
    {

    }

    public static MissPiggy Instance
    {
        get { return _instance.Value; }
    }
}

答案 1 :(得分:0)

singleton<t>是通用类型-没有通用类型参数,您将无法引用它。

实际上,它实际上是在生成新类型。

因此,当您这样做时:

var mainSingleton = singleton<main>.instance;

它实际上是在创建一个新的类型,如下所示:

public class NewGenericTypeWithWeirdName
{
    private readonly static Lazy<main> val = new Lazy<main>(() => new main());
    public static main instance { get { return val.Value; } }

    public int UserID { get; set; }
}

...并且,如果您声明var otherSingleton = singleton<SomethingElse>.instance;,它也会做同样的事情-它会创建与上面相同的另一种类型,只是将T替换为SomethingElse

这就是为什么您不能这样做:

singleton.instance.UserID

因为编译器不知道您指的是哪种类型。它是为singleton<main>生成的类型,还是为singleton<SomethingElse>生成的类型?它们实际上是不同的类型,这意味着它们的静态属性(包括UserID)将有所不同。

您可以这样做:

return data.GetUserFromID(singleton<main>.instance.UserID);
                                   ^^^^^^

...因为现在您要告诉它实际的类型-它是singleton<main>


请澄清一下,除非该类具有private构造函数且没有非私有构造函数,否则它不是单例。

您可以这样做:

var mainSingleton = singleton<main>.instance;

,它将始终返回main的相同实例。

但是您也可以这样做:

var m1 = new singleton<main>();
var m2 = new singleton<main>();

您可以创建多个实例,因此不是一个实例。要解决此问题,请将私有构造函数添加到singleton

private singleton(){}

现在只能在类中调用构造函数。这意味着获取实例的唯一方法是调用instance。每次执行此操作时,您都会得到一个相同的实例,所以现在它确实是一个单例。