2012-02-15 137 views
2

我有一个类,DataAdapter,它被我的站点实例化为单例对象。这个类有我想成为一个懒惰的单身一个人属性,代码来实现:.Net Singleton属性的延迟初始化

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模式)。

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

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

但是,这并不工作,因为这三个参数是不是静态的(他们是在当前的方法实例对象)。 writeupsI've found没有解决这个问题。我需要一些方法将这些值传递给该lambda表达式?懒惰<>类看起来像期待一个空的签名。

回答

0

(这三个参数传递给的PersonManager构造是对当前对象 属性/字段。)

构造函数被用于初始化对象。您尝试通过的参数目前没有赋值给它们的值。如果你的对象需要这些值被正确初始化,那么当你初始化时它们需要被传入。

虽然您可以将您的属性转换为方法并将这些值传递给静态GetInstance方法,但您只会在第一次调用GetInstance时设置一次。这可能不是一个好主意,但它可以完成。我会将你的Person属性转换为Method,并接受这些参数并使用它们初始化构造函数。这确实意味着你不会使用Lazy<T>,你的代码行会增加,但你会有更多可预测的行为。

+0

你不正确有关不具有价值,他们的对象的构造函数中赋值的对象。我没有得到一个空引用异常,我得到一个编译错误,因为这些字段找不到。 我不确定你的建议比我开始使用的(工作)双重检查锁解决方案要好。 – Arbiter 2012-02-15 18:17:21

+0

@Arbiter从初始化它们的代码中不清楚。 KeithS建议应该为你工作。我的第二个建议是不混合模式。 – sarvesh 2012-02-15 19:12:40

3

那么,如果Lazy使用Instance属性与单例的一个实例一起工作来为自己提供属性呢?这些字段仍然可以是私有的,因为我们正在从类内部使用它们(聪明),整个事情仍然是懒惰的,直到Singleton.Instance在执行过程中第一次被引用。但是,在代码尝试获取Person属性之前,私有字段必须具有适当的值。如果他们在Singleton实例化时急于加载,那很好。

C# In Depth借用,这是一个准懒惰的Singleton,带有一个完全惰性的Person成员,它使用一个引用Singleton的lambda进行初始化。

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,每一个依赖应该被注册和注入。使用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); 
} 
+0

一个好主意,但它不适合我。我没有使用像这样的静态属性来实现'Singleton',它被ninject注入为单例。如果'Singleton'在这种情况下不是单身人士,而是普通实例成员,你会怎么做? – Arbiter 2012-02-15 18:23:19

+0

@Arbiter:请参阅编辑。 – KeithS 2012-02-15 18:55:36

+0

'Singleton'目前有一个构造函数('client'对象不能在没有连接字符串的情况下被初始化)。如果我摆脱了构造函数,我需要修改我的注入以使用属性注入而不是构造函数注入,但是只是为了使用Lazy <>类而跳过了很多箍环。我认为这不是正确的工具。 – Arbiter 2012-02-15 19:11:50