Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/269.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C#自动实现属性的延迟加载_C#_.net_Reflection_Lazy Loading - Fatal编程技术网

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()

我正在努力做一些事情有三件事:

  • 属性为自动设置器/获取器(必需)
  • 属性是延迟加载(必需)
如何对C#自动属性进行延迟加载

为了实现上面的两件事,我想我需要使用
反射
(或者其他)。这就是我迄今为止所尝试的。我有一个对象测试:

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();
});
公共图书馆