.Net 单例属性的延迟初始化
我有一个类 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 构造函数的这三个参数是当前对象上的属性/字段。) 这段代码工作完美(它是一个双锁检查模式)。
但是,这是很多代码,我想使用新的 懒惰>>在 .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; } }
但这不起作用,因为这三个参数不是静态的(它们是当前方法上的实例对象)。 都没有写 ups 我发现< /a> 解决这个问题。我需要某种方法将这些值传递到 lambda 表达式中吗?懒惰者<>类看起来需要一个空签名。
I have a class, DataAdapter
which is instantiated as a singleton object by my site. That class has a Person property which I'd like to be a lazy singleton, the code to accomplish this:
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;
}
}
(those three arguments to the PersonManager constructor are properties/fields on the current object.)
This code works perfectly (it's a double-lock check pattern).
However, this is a lot of code, I'd like to make use of the new Lazy<> type in .Net 4.0 to make it simpler. So I change the code to:
private static readonly Lazy<IPersonManager> _person = new Lazy<IPersonManager>(() => new PersonManager(_adUserName, _adPassword, client));
public static IPersonManager Person { get { return _person.Value; } }
But this doesn't work, because those three parameters are not static (they're instance objects on the current method). None of the write ups I've found address this. I need some way to pass those values into that lambda expression? The Lazy<> class looks like it's expecting an empty signature.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
那么,如果 Lazy 使用 Instance 属性来处理单例的实例来为自己提供属性会怎么样?这些字段仍然可以是私有的,因为我们是在类内部使用它们(聪明),并且整个事情仍然会很懒惰,直到在执行期间第一次引用 Singleton.Instance 为止。但是,在代码尝试获取 Person 属性之前,私有字段必须具有正确的值。如果它们在 Singleton 实例化自身时被急切地加载,那就没问题。
借用C# In Depth,这是一个带有完全惰性 Person 成员的准惰性 Singleton使用引用 Singleton 的 lambda 进行初始化。
编辑:如果您有 IoC,请使用 IoC。您当前正在尝试混合模式;您正在使用 IoC 使用运行时规则将实例类“提升”为单例,然后尝试基于此人造单例的实例范围数据字段实例化编译器强制执行的惰性静态属性。 一旦你进入 IoC,这根本行不通
,每个依赖项都应该被注册和注入。使用 Ninject 注册 PersonManager 作为 IPersonManager 实现,然后为主单例 DataAdapter 创建一个构造函数,该构造函数可以被赋予一个生成 IPersonManager 的 Func。您通常可以为此目的定义一个自定义函数,在您的情况下,该函数将利用 IoC 从容器中保存的单个 DataAdapter 实例提供所需的实例数据。
警告:这些数据字段现在必须是公开可读的,以避免一些严重丑陋的反映;您可以将字段定义为只读字段或只读属性,以防止人们篡改它们,但您的消费者将能够看到它们。
编辑2:这是我的想法:
Well, what if the Lazy used the Instance property to work with an instance of your singleton to provide itself with the properties? Those fields can still be private since we're working with them from inside the class (clever), and the whole thing will still be lazy until Singleton.Instance is referenced for the first time during execution. However, the private fields MUST have proper values before your code attempts to get the Person property. If they're eagerly loaded when Singleton instantiates itself, that's fine.
Borrowing from C# In Depth, here's a quasi-lazy Singleton with a fully-lazy Person member initialized using a lambda that references the Singleton.
EDIT: If you have IoC, use IoC. You are currently trying to mix patterns; you're using IoC to "promote" an instance class to singleton using runtime rules, but then trying to instantiate a compiler-enforced lazy static property based on this faux-singleton's instance-scoped data fields. This is simply not going to work
Once you go IoC, EVERY dependency should be registered and injected. Register PersonManager with Ninject as the IPersonManager implementation, and then create a constructor for your main singleton DataAdapter that can be given a Func that produces an IPersonManager. You can usually define a custom function for this purpose, which in your case will leverage the IoC to provide the required instance data from the single DataAdapter instance kept in the container.
Caveat: those data fields must now be publicly readable to avoid some seriously ugly reflection; you can define the fields as read-only fields or get-only properties to prevent people tampering with them, but your consumers will be able to see them.
EDIT 2: Here's what I had in mind:
构造函数用于初始化对象。此时,您尝试传递的参数将没有分配任何值。如果您的对象需要正确初始化这些值,则需要在初始化时传入它们。
尽管您可以将属性转换为方法并将这些值传递给静态 GetInstance 方法,但您只需在第一次调用 GetInstance 时设置一次。这可能不是一个好主意,但可以做到。我会将 Person 属性转换为 Method 并接受这些参数并使用它们来初始化构造函数。这确实意味着您不会使用
Lazy
并且您的代码行数将会增加,但您的行为将更加可预测。A constructor is used to initialize your object. The arguments you are trying to pass will have no value assigned to them at this point. If your object needs these values to be initialized properly then they need to be passed in when you initialize.
Although you can convert your property to a method and pass these values to a static GetInstance method you will only setting this once, the first time GetInstance is called. This is probably not a good idea but it can be done. I would convert you Person property to a Method and accept these parameters and use them to initalize the constructor. This does mean you won't be using
Lazy<T>
and your lines of code will increase but you will have much more predictable behavior.