目前,我正在C#中试验泛型,并对自己提出了以下挑战:
给定一个泛型函数f<T>,在编译期间验证T是来自给定集T1、T2、.、Tn的类型。例如,如果在f<T>中我们有
CompileTimeAssert<T>.isContainedIn<TypeList<string, int, bool>>();然后f<int>应该编译,而f<double>不应该编译。
我还没到呢。到目前为止,这就是我所拥有的:
interface ContainsType<T> {}
class TypeList<T1>: ContainsType<T1> {}
class TypeList<T1, T2>: TypeList<T2>, ContainsType<T1> {}
class TypeList<T1, T2, T3>: TypeList<T2, T3>, ContainsType<T1> {}
class TypeList<T1, T2, T3, T4>: TypeList<T2, T3, T4>, ContainsType<T1> {}
// add longer type lists to taste
class CompileTimeAssert<T>
{
public static void isContainedIn<TypeList>()
where TypeList: ContainsType<T> {}
public static void isContainedIn<TypeList>(TypeList tl)
where TypeList: ContainsType<T> {}
}鉴于上述代码,如下所示(如预期):
// uses first overload
CompileTimeAssert<int>.isContainedIn<TypeList<string, int, bool>>();
var myTypeList = new TypeList<string, bool>();
CompileTimeAssert<string>.isContainedIn(myTypeList); // uses second overload以下内容也未按预期进行汇编:
CompileTimeAssert<short>.isContainedIn<TypeList<string, int, bool>>();
var myTypeList = new TypeList<string, bool>();
CompileTimeAssert<double>.isContainedIn(myTypeList);这一切都很可爱,但也没用。如果一个人能够做到以下几点,就会变得更加有用:
void f<T>()
{
CompileTimeAssert<T>.isContainedIn<TypeList<string, int, bool>>();
}然后让f<int>编译,f<double>会导致编译错误。
唉,上面给出的f<T>无法编译(不管有什么具体类型的调用)。我得到了以下错误(在Mac上使用MonoDevelop ):
Error CS0311:从
TypeList<string,int,bool>' cannot be used as type parameter 'TypeList' in the generic type or method 'CompileTimeAssert<T>.isContainedIn<TypeList>()'. There is no implicit reference conversion fromTypeList到ContainsType的类型
我有点理解为什么这不起作用,但到目前为止,我还没有想出一个可行的办法。有没有人知道在C#中我想要的东西是否是可能的?
谢谢。
发布于 2011-12-29 15:37:36
挑战的目标是无用的,因为.NET的泛型与编译时构造一样是运行时结构。即使您的程序编译没有错误,仍然可以通过反射扩展您的泛型,传递“未经批准”的类型。
我知道您是从哪里来的(我也非常喜欢Alexandrescu的那本书),但是了解C#泛型的一个重要方面是,泛型不是C++模板。除了小的句法相似性,他们甚至没有那么接近:“不是相同的大概,不是同一个联盟,甚至不是同一项运动”。需要进行编译时验证的主要驱动力是:"ints是好的,双行不是OK的),您可以隐式地访问操作:如果在模板扩展中提供的a和b类型允许+操作,那么+就会成功。在C#中不一样:如果希望对传递给泛型的值执行操作,则必须通过类型约束显式地规定该操作的存在,或者提供执行该操作的显式方法(委托、接口等)。无论哪种方式,告诉编译器您的模板适用于ints,而不是双倍,这绝对不会为您买到任何东西。
发布于 2011-12-29 15:42:54
我看不出你想做的事怎么可能是仿制药。
这样一个泛型类的目的是什么(这里没有编译,这里给出了示例):
public class GenericClass<T>
where T : A
where T : B
where T : C
{
public T MyMember { get; set; }
public GenericClass(T myMember)
{
this.MyMember = myMember;
}
}MyMember实现什么逻辑?如果A、B、anc有一些共同点,那么所有类都实现一个特定的接口或继承相同的基类,那么的where
发布于 2011-12-29 15:44:06
这是行不通的,因为C#泛型函数只需要通过基于约束的类型检查。不考虑实际的类型参数,因为泛型不是专门化的。
您所承诺的唯一的事情就是(隐式地) T : object。
所以编译器类型检查
CompileTimeAssert<object>.isContainedIn<TypeList<string, int, bool>>();这(正确)无法编译。
另一方面,你可以写:
void f<T>() where T : Form
{
CompileTimeAssert<T>.isContainedIn<TypeList<string, Control>>();
}而且它会编译,因为每个Form都是-一个Control。
https://stackoverflow.com/questions/8663342
复制相似问题