c# - .Net 单例属性的延迟初始化

标签 c# c#-4.0 singleton lazy-loading lazy-initialization

我有一个类,DataAdapter,它由我的站点实例化为单例对象。该类有一个 Person 属性,我希望它是一个惰性单例,完成此操作的代码:

private readonly object _personLock = new object();
private volatile IPersonManager _person;
public IPersonManager Person
{
    get
    {
        if (_person == null)
        {
            lock (_personLock)
            {
                if (_person == null)
                {
                    _person = new PersonManager(_adUserName, _adPassword, client);
                }
            }
        }
        return _person;
    }
}

(PersonManager 构造函数的这三个参数是当前对象的属性/字段。) 这段代码运行完美(这是一个 double-lock check 模式)。

但是,这是很多代码,我想利用新的 Lazy<> type在.Net 4.0中使其变得更简单。所以我将代码更改为:

    private static readonly Lazy<IPersonManager> _person = new Lazy<IPersonManager>(() => new PersonManager(_adUserName, _adPassword, client));
    public static IPersonManager Person { get { return _person.Value; } }

但这不起作用,因为这三个参数不是静态的(它们是当前方法的实例对象)。 write 都没有ups I've found解决这个问题。我需要某种方法将这些值传递到 lambda 表达式中吗? Lazy<> 类看起来需要一个空签名。

最佳答案

那么,如果 Lazy 使用 Instance 属性来处理单例的实例来为自己提供属性会怎么样?这些字段仍然可以是私有(private)的,因为我们是在类内部使用它们(聪明),并且整个事情仍然会很懒惰,直到在执行期间第一次引用 Singleton.Instance 为止。但是,在代码尝试获取 Person 属性之前,私有(private)字段必须具有正确的值。如果它们在 Singleton 实例化自身时被急切地加载,那就没问题。

借用C# In Depth ,这是一个准惰性单例,其中包含使用引用该单例的 lambda 初始化的完全惰性 Person 成员。

public sealed class Singleton
{
    private static readonly Singleton instance = new Singleton();

    // Explicit static constructor to tell C# compiler
    // not to mark type as beforefieldinit
    static Singleton()
    {
    }

    private Singleton()
    {
       //I HIGHLY recommend you initialize _adusername, 
       //_adpassword and client here.
    }

    public static Singleton Instance
    {
        get
        {
            return instance;
        }
    }

    private static readonly Lazy<IPersonManager> _person = 
       new Lazy<IPersonManager>(() => new PersonManager(Instance._adUserName, Instance._adPassword, Instance.client));
    public static IPersonManager Person { get { return _person.Value; } }

    private object _adUserName;
    private object _adPassword;
    private object client;
}

public class PersonManager:IPersonManager {}

public interface IPersonManager{}

编辑:如果您有 IoC,请使用 IoC。您当前正在尝试混合模式;您正在使用 IoC 使用运行时规则将实例类“提升”为单例,然后尝试基于此人造单例的实例范围数据字段实例化编译器强制执行的惰性静态属性。这根本行不通

一旦进入 IoC,每个依赖项都应该被注册和注入(inject)。使用 Ninject 注册 PersonManager 作为 IPersonManager 实现,然后为主单例 DataAdapter 创建一个构造函数,该构造函数可以被赋予一个生成 IPersonManager 的 Func。您通常可以为此目的定义一个自定义函数,在您的情况下,该函数将利用 IoC 从容器中保存的单个 DataAdapter 实例提供所需的实例数据。

警告:这些数据字段现在必须是公开可读的,以避免一些严重丑陋的反射;您可以将字段定义为只读字段或只获取属性,以防止人们篡改它们,但您的消费者将能够看到它们。

编辑 2:这是我的想法:

//in your Ninject bindings:
kernel.Bind<DataAdapter>().ToSelf().InSingletonScope();
kernel.Bind<PersonManager>().ToSelf().InSingletonScope();
//to bind the interface
kernel.Bind<IPersonManager>()
   .ToMethod(c =>{ 
      var adapter = kernel.Get<DataAdapter>();
      //this is why these fields would have to be public
      var arg1 = new ConstructorArgument("adUserName", adapter._adUserName)
      var arg2 = new ConstructorArgument("adPassword", adapter._adPassword)
      var arg3 = new ConstructorArgument("client", adapter.client)
      //the names of the arguments must match PersonManager's constructor
      c.Kernel.Get<PersonManager>(arg1, arg2, arg3);
   });

//now in your DataAdapter, specify a constructor like this, and Ninject will provide:

public DataAdapter(Func<IPersonManager> personFunc)
{
   //_person should obviously not be instantiated where it's defined in this case
   _person = new Lazy<IPersonManager>(personFunc);
}

关于c# - .Net 单例属性的延迟初始化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9297500/

相关文章:

c# WebService 杀死它拥有的 Singleton

ios - 从类方法中获取对 sharedInstance 的访问

c# - 服务器标签格式不正确?

c# - 传递 Func<TSource, TKey> keySelector 错误

c# - 多个 Regex.Replace 或 or'ed 模式?

javascript - 在 asp.net c# 中禁用浏览器的自动完成文本框

asp.net-mvc-3 - MVC 3、单选按钮和模型

c# - 启用/禁用 MVC 项目中的链接

c# - 空指针测试性能

iphone - UIViewController 作为单例