C#自动实现属性的延迟加载
我正在努力做一些事情有三件事:C#自动实现属性的延迟加载,c#,.net,reflection,lazy-loading,C#,.net,Reflection,Lazy Loading,我正在努力做一些事情有三件事: 属性为自动设置器/获取器(必需) 属性是延迟加载(必需) 如何对C#自动属性进行延迟加载 为了实现上面的两件事,我想我需要使用反射(或者其他)。这就是我迄今为止所尝试的。我有一个对象测试: public class MyClass { private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() => new MyObjectClass()
- 属性为自动设置器/获取器(必需)
- 属性是延迟加载(必需)
反射(或者其他)。这就是我迄今为止所尝试的。我有一个对象测试:
public class MyClass
{
private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() => new MyObjectClass());
public MyObjectClass MyObject { get { return lazyObjectClass.Value; } }
}
但是,当我通过Reflection
将值设置为MyObject
时,MyObjectClass
也被初始化。我如何解决这个问题,或者让我知道是否应该使用完全不同的解决方案。简短回答
您可能不喜欢它,但不能对自动实现的属性u̲n̲l̲e̲s̲进行延迟加载:
- 您有一个容器/工厂,它在类上创建一个代理,并通过代理处理延迟加载
- 或者您有一些机制,比如使用编织工具在构建时操作生成的IL,并将延迟加载特性添加到类中
我怀疑您是否真的需要自动实现属性的延迟加载。因此,我的建议是:更改代码,忘记自动实现的属性,使用自定义getter和setter轻松地使用延迟加载(有或没有使用lazy
)
无论如何,如果你想知道更多,请阅读详细的答案
注意:通过做一些研究,你可能会在stackoverflow中找到一些试图解决类似问题的帖子,例如:,或。我试图在本文中分享更多细节/选项。你也可能会发现链接帖子很有用
详细答案-自动实现属性的延迟加载
你想在你的班上有一个
正如简短回答中已经提到的,您不能对自动实现的属性进行延迟加载,除非:
- 您有一个容器/工厂,它在类上创建一个代理,并通过代理处理延迟加载
- 或者您有一些机制,比如使用编织工具在构建时操作生成的IL,并将延迟加载特性添加到类中
例如,在实体框架中,可以对虚拟自动属性进行延迟加载。但问题是,它由实体框架处理,在这种情况下,它为对象创建代理
自动实现属性的延迟加载-选项
要实施上述解决方案之一,您可以使用以下选项:
要扩展解决方案,可以使用以下方法生成代理并在代理中处理延迟加载:
- 自己实现代理类:您可以创建从主类派生的代理类,然后重写要延迟加载的属性。然后,您可以在DI容器中注册派生类,并在作为主类实例请求时返回派生类的实例
- 实现一个通用工厂,以便在运行时使用
反射创建代理。Emit
:您可以创建一个通用工厂方法,以便在运行时使用或其他运行时程序集生成机制创建代理
- 使用
RealProxy
实现一个通用工厂以在运行时创建代理。您可以创建一个通用工厂,使用并截获属性的getter和setter,并将延迟加载功能添加到代理的属性中
- 依赖DI框架的拦截功能:您可以使用DI框架的拦截功能(如果它具有此类功能),拦截get和set并实现延迟加载。例如,您可以在Unity中使用拦截器实现该功能
- 依赖编织工具在构建时操纵程序集:您可以依赖AOP框架和编织工具(如或)操纵程序集的IL,并使属性在编译时可延迟加载。例如,您可以找到PostSharp的实现
问题与get方法有关
在第一种情况下,您有:
public class MyClass
{
private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() => new MyObjectClass());
public MyObjectClass MyObject { get { return lazyObjectClass.Value;** } }
}
公共类MyClass
{
private Lazy lazyObjectClass=new Lazy(()=>new MyObjectClass());
公共MyObject类MyObject{get{return lazyObjectClass.Value;**}
}
当您访问MyObject时,实际上您调用了一个从lazyObjectClass读取的get方法,因此lazyObjectClass只有在被调用时才被求值
在第二种情况下,使用自动属性,但实际代码如下所示:
public class MyClass
{
public MyClass()
{
//Get field
var field = this.GetType().GetField("lazyObjectClass", BindingFlags.NonPublic | BindingFlags.Instance);
//Get value of field
Lazy<MyObjectClass> lazyValue = (Lazy<MyObjectClass>)field.GetValue(this);
//Get property MyObject
var property = this.GetType().GetProperty("MyObject");
//Set value to the MyObject
property.SetValue(this, lazyValue.Value); // <- when It called, MyObjectClass is ititialize too
}
private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() => new MyObjectClass());
public MyObjectClass MyObject { get; set; }
}
public class MyClass
{
private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() => new MyObjectClass());
private MyObjectClass <MyObject>k__BackingField;
public MyObjectClass MyObject
{
get
{
return <MyObject>k__BackingField;
}
set
{
<MyObject>k__BackingField = value;
}
}
}
公共类MyClass
{
private Lazy lazyObjectClass=new Lazy(()=>new MyObjectClass());
私人MyObjectClass k_uBackingfield;
公共MyObject类MyObject
{
得到
{
返回k__BackingField;
}
设置
{
k__BackingField=值;
}
}
}
但有一个问题,get方法直接从隐藏的自动生成的k_ubackingfield读取,该字段必须已经求值,没有对lazy的调用,并且不能使用反射更改get实现
没有办法做到您所想的,但我建议以下解决方法:
public class MyObjectClass
{
}
public class MyClass
{
public MyClass()
{
var field = this.GetType().GetField("lazyObjectClass", BindingFlags.NonPublic | BindingFlags.Instance);
//Get value of field
Lazy<MyObjectClass> lazyValue = (Lazy<MyObjectClass>)field.GetValue(this);
//Get property MyObject
var lazyField = this.GetType().GetField("_lazy", BindingFlags.NonPublic | BindingFlags.Instance);
lazyField.SetValue(this, lazyValue);
}
private Lazy<MyObjectClass> _lazy = null;
private MyObjectClass myValue = null;
private Lazy<MyObjectClass> lazyObjectClass = new Lazy<MyObjectClass>(() =>
{
return new MyObjectClass();
});
public MyObjectClass MyObject
{
get
{
if (myValue == null)
{
return _lazy.Value;
}
else
{
return myValue;
}
}
set
{
myValue = value;
}
}
}
class Program
{
static void Main(string[] args)
{
MyClass myClass = new MyClass();
var a = myClass.MyObject;
}
}
公共类MyObject类
{
}
公共类MyClass
{
公共MyClass()
{
var field=this.GetType().GetField(“lazyObjectClass”,BindingFlags.NonPublic | BindingFlags.Instance);
//获取字段的值
Lazy lazyValue=(Lazy)field.GetValue(this);
//获取属性MyObject
var lazyField=this.GetType().GetField(“_lazy”,BindingFlags.NonPublic | BindingFlags.Instance);
SetValue(这个,lazyValue);
}
private Lazy _Lazy=null;
私有MyObject类myValue=null;
私有Lazy lazyObjectClass=新的Lazy(()=>
{
返回新的MyObjectClass();
});
公共图书馆