代码之家  ›  专栏  ›  技术社区  ›  Cristian Diaconescu

Lazy<t>实现和.NET泛型

  •  15
  • Cristian Diaconescu  · 技术社区  · 14 年前

    我在寻找进行懒惰初始化的方法 Lazy<T> 它包含在.NET 4中。

    我正在考虑滚动我自己的实现 懒惰&懒惰; 对于.NET 3.5(使用更简单的多线程策略),我遇到了以下问题:

    Lazy基本上有两种类型的构造函数:

    class Lazy<T> {
    
        public Lazy(){...} // ctor #1
    

    它使用t的默认构造函数创建t的实例,并且

        public Lazy(Func<T> func){...} // ctor #2
    

    它让调用者决定如何创建T的实例。

    现在的问题是:

    如果我想对第一个ctor进行编译时检查,我将添加一个限制

    class Lazy<T> where T: new() {...}
    

    在班级层面。这可以让我用 new T() 创建实例;但第二个ctor不需要此限制,更糟的是,它还限制了我可以使用的类型(对于具有默认ctor的类型)

    如果我想在第二个ctor中使用任何类型,我不会设置任何限制,并且在第一个ctor中使用反射来确保 T 没有默认的ctor。但是,这种方法将缺少编译时检查,并且仅在第一个ctor与错误类型一起使用时引发运行时异常。

    我的问题是:我能两全其美吗?

    理想情况下,我希望每次使用ctor_1时都进行编译时检查,但同时能够对没有默认ctor的类型使用ctor_2。

    Microsoft实现是如何做到这一点的?(我不容易访问.NET 4源或DLL)。

    编辑:(在“反射”MS组件之后)

    我检查了引用实现,它不进行编译时检查。
    它对“默认ctor”情况使用反射,当然,如果情况变糟,还会伴随运行时异常。

    5 回复  |  直到 13 年前
        1
  •  12
  •   Marc Gravell    14 年前

    我希望内置实现只使用 Activator.CreateInstance<T> 为了简单。我能想到的最干净的欺骗方式是在一个单独的工厂:

    // non-generic factory class with generic methods
    public static class Lazy {
        public static Lazy<T> Create<T>() where T : new() {
            return Create<T>(() => new T());
        }
        public static Lazy<T> Create<T>(Func<T> ctor) { ... }
    }
    public class Lazy<T> { ... }
    
        2
  •  7
  •   LBushkin    14 年前

    可以使用静态工厂方法而不是构造函数的重载:

    public class Lazy<T>
    {
        public Lazy( Func<T> f ) { /*...*/ }
    
       public static Lazy<R> Default<R>() where R : T, new()
       {
           return new Lazy<R>( () => new R() );
       }
    }
    

    现在,这会破坏与.NET 4.0版本的兼容性(在某种程度上)。 Lazy<T> 但它确实实现了两种类型的使用的编译时安全性。

    您可以通过为 懒惰&懒惰; 内部受保护,并提供一个静态工厂类,用于创建实例:

    public static class Lazy {
        static Lazy<T> Create<T>( Func<T> ) { ... }
        static Lazy<T> Create<T>( ) where T : new() { ... }
    }
    
        3
  •  2
  •   µBio    14 年前

    为什么不下载并行扩展并安装 Lazy<T> 3.5? Direct link

        4
  •  0
  •   TomTom    14 年前

    我的问题是:我能充分利用 两个世界?

    不。

    基本上,您没有编译时可检查的约束。

        5
  •  0
  •   jasonhooten    13 年前

    像这样的东西应该对你有用。在转到4.0之前,我们在本地代码库中使用了一年左右。

    public class Lazy<T> {
      private Func<T> func;
      private T result;
      private bool hasValue;
      public Lazy(Func<T> func) {
        this.func = func;
        this.hasValue = false;
      }
      public T Value {
        get {
          if (!this.hasValue) {
            this.result = this.func();
            this.hasValue = true;
          }
          return this.result;
        }
      }
    }