通常我们不能将类型参数限制为T
从密封类型(例如struct
类型)派生。这将毫无意义,因为只有一种类型可以适合,因此不需要泛型。所以约束如下:
where T : string
或者:
where T : DateTime
是非法的,这是有充分理由的。
但是,当约束到另一个类型参数时,有时会在另一个类型参数被“替换”为实际类型(恰好是密封的)时发生这种情况。考虑类:
abstract class ExampleBase<TFromType>
{
internal abstract void M<TFromMethod>(TFromMethod value) where TFromMethod : TFromType;
}
这是很无辜的。在具体化中:
class ExampleOne : ExampleBase<string>
{
internal override void M<TFromMethod>(TFromMethod strangeString)
{
var a = string.IsNullOrEmpty(strangeString);
Console.WriteLine(a);
var b = strangeString.Substring(10, 2);
Console.WriteLine(b);
}
}
我们使TFromType
等于string
。这可能是有意义的。以外的其他成员M<>
。但M<>
本身仍然可以使用:代码:
var e1 = new ExampleOne();
e1.M("abcdefghijklmnopqrstuvwxyz");
将运行并写入:
错误的 吉隆坡
到控制台。所以约束基本上变成了where TFromMethod : string
,但事情仍然很好。
这个问题是关于如果TFromType
是值类型会发生什么。所以这次我们这样做:
class ExampleTwo : ExampleBase<DateTime>
{
internal override void M<TFromMethod>(TFromMethod strangeDate)
{
// var c = DateTime.SpecifyKind(strangeDate, DateTimeKind.Utc); // will not compile
// var d = strangeDate.AddDays(66.5); // will not compile
var e = string.Format(CultureInfo.InvariantCulture, "{0:D}", strangeDate); // OK, through boxing
Console.WriteLine(e);
var f = object.ReferenceEquals(strangeDate, strangeDate);
Console.WriteLine("Was 'strangeDate' a box? " + f);
}
}
那么为什么不允许来自c
and声明的调用呢?d
毕竟strangeDate
编译时类型TFromMethod
被限制为DateTime
. 所以肯定strangeDate
是隐含的DateTime
?毕竟,这适用于string
(class ExampleOne
上面)。
我更喜欢在官方 C# 语言规范中提到相关位置的答案。
请注意,当尝试添加时d
,键入strangeDate.Ad
... 会使 IntelliSense(Visual Studio 的自动完成器)列出所有可访问的实例成员的列表DateTime
,因此很明显 IntelliSense 认为调用d
应该是合法的!
当然,在注释掉 and 之后,我们可以使用c
( with and ),代码如下:d
ExampleTwo
e
f
var e2 = new ExampleTwo();
e2.M(new DateTime(2015, 2, 13));
运行并写出:
2015 年 2 月 13 日星期五 'strangeDate' 是一个盒子吗?错误的