首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C#中用户定义的编译时类型约束

C#中用户定义的编译时类型约束
EN

Stack Overflow用户
提问于 2011-12-29 02:15:57
回答 3查看 2K关注 0票数 3

目前,我正在C#中试验泛型,并对自己提出了以下挑战:

给定一个泛型函数f<T>,在编译期间验证T是来自给定集T1、T2、.、Tn的类型。例如,如果在f<T>中我们有

代码语言:javascript
复制
CompileTimeAssert<T>.isContainedIn<TypeList<string, int, bool>>();

然后f<int>应该编译,而f<double>不应该编译。

我还没到呢。到目前为止,这就是我所拥有的:

代码语言:javascript
复制
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> {}
}

鉴于上述代码,如下所示(如预期):

代码语言:javascript
复制
 // uses first overload
CompileTimeAssert<int>.isContainedIn<TypeList<string, int, bool>>();

var myTypeList = new TypeList<string, bool>();
CompileTimeAssert<string>.isContainedIn(myTypeList); // uses second overload

以下内容也未按预期进行汇编:

代码语言:javascript
复制
CompileTimeAssert<short>.isContainedIn<TypeList<string, int, bool>>();

var myTypeList = new TypeList<string, bool>();
CompileTimeAssert<double>.isContainedIn(myTypeList);

这一切都很可爱,但也没用。如果一个人能够做到以下几点,就会变得更加有用:

代码语言:javascript
复制
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#中我想要的东西是否是可能的?

谢谢。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-12-29 15:37:36

挑战的目标是无用的,因为.NET的泛型与编译时构造一样是运行时结构。即使您的程序编译没有错误,仍然可以通过反射扩展您的泛型,传递“未经批准”的类型。

我知道您是从哪里来的(我也非常喜欢Alexandrescu的那本书),但是了解C#泛型的一个重要方面是,泛型不是C++模板。除了小的句法相似性,他们甚至没有那么接近:“不是相同的大概,不是同一个联盟,甚至不是同一项运动”。需要进行编译时验证的主要驱动力是:"ints是好的,双行不是OK的),您可以隐式地访问操作:如果在模板扩展中提供的ab类型允许+操作,那么+就会成功。在C#中不一样:如果希望对传递给泛型的值执行操作,则必须通过类型约束显式地规定该操作的存在,或者提供执行该操作的显式方法(委托、接口等)。无论哪种方式,告诉编译器您的模板适用于ints,而不是双倍,这绝对不会为您买到任何东西。

票数 3
EN

Stack Overflow用户

发布于 2011-12-29 15:42:54

我看不出你想做的事怎么可能是仿制药。

这样一个泛型类的目的是什么(这里没有编译,这里给出了示例):

代码语言:javascript
复制
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;
    }
}

  • 如果它的意思是"T必须是A、B和C",那么就不可能因为在C#中不存在多重继承。如果它的意思是"T必须是A、B或C",那么:
    • ,如果A、B和C没有任何共同之处,那么GenericClass就没有目的:当三个类没有任何共同点时,您会用MyMember实现什么逻辑?如果A、B、anc有一些共同点,那么所有类都实现一个特定的接口或继承相同的基类,那么
    • 会实现什么逻辑?并且您将使用这个接口或基类作为constraint.

where

票数 0
EN

Stack Overflow用户

发布于 2011-12-29 15:44:06

这是行不通的,因为C#泛型函数只需要通过基于约束的类型检查。不考虑实际的类型参数,因为泛型不是专门化的。

您所承诺的唯一的事情就是(隐式地) T : object

所以编译器类型检查

代码语言:javascript
复制
CompileTimeAssert<object>.isContainedIn<TypeList<string, int, bool>>();

这(正确)无法编译。

另一方面,你可以写:

代码语言:javascript
复制
void f<T>() where T : Form
{
    CompileTimeAssert<T>.isContainedIn<TypeList<string, Control>>();
}

而且它会编译,因为每个Form都是-一个Control

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/8663342

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档