2011-05-12 42 views
8

所以这就是我想要做的。where子句在C#中的构造函数?

我正在创建一个泛型类,该泛型类以两种方式之一分配由泛型参数指定的类型,这由使用的重载构造函数决定。

这里是例如:

class MyClass<T> 
    where T : class 
{ 
    public delegate T Allocator(); 
    public MyClass() 
    { 
     obj = new T(); 
    } 

    public MyClass(Allocator alloc) 
    { 
     obj = alloc(); 
    } 

    T obj; 
} 

这类需要类型T是在所有情况下RefType的。对于默认的构造函数,我们想通过默认的构造函数实例化T。我想放where T : new()我的默认构造函数,像这样:

public MyClass() 
    where T : new() 
{ 
    obj = new T(); 
} 

然而,这不是有效的C#。基本上我只想添加对T类型的约束,只有在使用MyClass()的默认构造函数时才有默认构造函数。

在MyClass的第二个构造函数中,我们让用户决定如何用自己的分配方法为T分配,所以很明显,MyClass在所有情况下都不强制默认构造。

我有一种感觉,我需要在默认的构造函数中使用反射,但我希望不会。

我知道这可以这样做,因为.NET 4.0中的Lazy<T>类不要求T在类级别默认构造,但它具有类似于我的示例中的构造方法。我想知道Lazy<T>至少如何。

回答

8

您只能在引入泛型类型参数的声明中包含约束条件。

但是,你可以在一个非通用引入通用方法:(我个人只是用Func<T>,而不是顺便说一句,宣布独立的委托类型)

public class MyClass 
{ 
    public static MyClass<T> Create<T>() where T : class, new() 
    { 
     return new MyClass<T>(() => new T()); 
    } 
} 

public class MyClass<T> where T : class 
{ 
    T obj; 

    public MyClass(Allocator allocator) 
    { 
     obj = allocator(); 
    } 
} 

然后你可以使用:

MyClass<Foo> foo = MyClass.Create<Foo>(); // Enforces the constraint 
+0

改变我对这个的答案......我在'Activator.CreateInstance ()'上做了一些阅读,事实上它不会在编译时检查默认构造(我更喜欢)。我去了泛型工厂类。 – 2011-05-12 13:44:08

+0

如何在不使用'partial'关键字的情况下两次定义MyClass?我不熟悉这个语法。 – 2011-05-13 14:36:29

+1

@Robert Dailey:我还没有声明MyClass两次 - 我声明了MyClass(非泛型)和MyClass(泛型只有一个类型参数)。它们是不同的类型,就像'Nullable'和'Nullable '是不同的类型。 – 2011-05-13 14:41:04

7

基本上我只想添加约束类型T有默认的构造函数只有当默认的构造函数MyClass()被使用。

不可能在T上强制执行此约束。您可能有这种情况,where T : new()是在MyClass<T>的定义中指定的,或者根本没有这种限制。

我有一种感觉,我需要在默认的构造函数中使用反射,但我希望不会。

你不能强制约束,但你能说

obj = Activator.CreateInstance<T>(); 

这将调用默认构造函数T

我知道这是可以做到的,因为.NET 4.0中的Lazy类不要求T在类级别缺省构造,但它具有类似于我的示例中的构造函数。我想知道懒惰至少如何。

Lazy<T>要求您指定一个委托,该委托返回实例T。基本上,它要求你指定一个Func<T>

+0

你可以* *强制约束 - 不只是在T他的构造函数。在别处的通用方法中引入它可以很好地工作。 – 2011-05-12 13:28:02

+0

@Jon Skeet:OP所要求的约束不能在通用类“MyClass ”定义的类型参数“T”上实施。 – jason 2011-05-12 17:29:28

+0

不是在类型本身上,不是......但是您可以在非泛型类型上创建一个简单的泛型方法,并使用它来代替公共无参数构造函数 - 请参阅我的答案。我的理解是,提供一种简单但编译时安全的方法,使用'T'的无参数构造函数来创建'MyClass'的实例。我的答案就是这样。 – 2011-05-12 17:41:35

3

你可以尝试使用Activator

class MyClass<T> where T : class 
{ 
    public MyClass() 
    { 
     obj = Activator.CreateInstance<T>(); 
    } 
} 
+0

也是:'Activator.CreateInstance ()' – 2011-05-12 13:23:39

+0

这会将检查留给执行时间,这不是理想的IMO。 – 2011-05-12 13:24:08

+0

'Activator.CreateInstance ()'只在运行时检查它是否是默认可构造的? – 2011-05-12 13:37:56

-2

那么,你需要或者有约束或没有。事实证明,懒惰使用Activator来创建一个实例。 下面是 Lazy<T>的工作原理 在版权问题的情况下删除的代码。

+2

我不确定.NET BCL代码的许可证是否允许在Internet上发布它... – 2011-05-12 13:23:53

+0

已注意。锁定我,扔掉钥匙! – 2011-05-12 13:25:07

+0

这是什么回应? – 2011-05-12 13:26:29