通常,我们不能将类型参数T约束为从密封类型(例如结构类型)派生.这将毫无意义,因为只有一种类型可以适合,因此不需要泛型.所以约束如下:
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");
将运行并写:
False kl
到控制台.所以约束基本上变成了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和d声明的调用呢?毕竟strangeDate有编译时类型TFromMethod,它被约束为DateTime.所以,奇怪的日期是隐含的DateTime吗?毕竟,这适用于字符串(上面的类ExampleOne).
我希望得到一个答案,它提到了官方C#语言规范中的相关位置.
请注意,在尝试添加d时,键入strangeDate.Ad …使IntelliSense(Visual Studio的自动完成程序)提供了DateTime的所有可访问实例成员的列表,因此很明显IntelliSense认为d中的调用应该是合法的!
当然,在c和d被注释掉后,我们可以使用ExampleTwo(带e和f),代码如下:
var e2 = new ExampleTwo();
e2.M(new DateTime(2015, 2, 13));
运行并写出:
Friday, 13 February 2015 Was 'strangeDate' a box? False
最佳答案 引用C#5.0规范:
6.1.10 Implicit conversions involving type parameters
The following implicit conversions exist for a given type parameter
T
:
From
T
to its effective base classC
, fromT
to any base class ofC
, and fromT
to any interface implemented byC
. […][…]
10.1.5 Type parameter constraints
The effective base class of a type parameter
T
is defined as follows:
- […]
- If
T
has no class-type constraint but has one or more type-parameter constraints, its effective base class is the most encompassed type (§6.4.2) in the set of effective base classes of its type-parameter constraints. The consistency rules ensure that such a most encompassed type exists.- […]
For the purpose of these rules, if
T
has a constraintV
that is a value-type, use instead the most specific base type ofV
that is a class-type. This can never happen in an explicitly given constraint, but may occur when the constraints of a generic method are implicitly inherited by an overriding method declaration or an explicit implementation of an interface method.These rules ensure that the effective base class is always a class-type.
换句话说,给定U = T约束,其中T = string,U的有效基类是字符串.给定U = T约束,其中T = DateTime,U的有效基类不是DateTime,而是ValueType.并且类型参数的唯一相关隐式转换是从类型参数类型到其有效基类.
这似乎会导致一些相当奇怪的行为,正如你所发现的那样,但它必须是一个有意识的决定,因为它已被明确地说明你的行为方式.
我猜想,这项工作会给编译器带来困难,有些情况下编译器会假定它在这种情况下处理引用类型,并且使其工作的好处很小.但就是这样:一个猜测.