.NET 中的泛型类型参数本身必须是类型。您不能创建仅特定于 Generic 类型参数的特定值的泛型类型/方法。
如果您不希望或无法创建表示您希望方法被限制为的属性值的类型,则必须在方法中进行完整性检查,以确保在提供的“foo”对象中使用正确的属性值。
使用特定类型作为特定属性值的表示可能是您所询问问题的答案,但它的缺点是不支持 switch-case 语句(请参见下文)。另请阅读我答案末尾的最后一条说明。
比如说,你想要一个代表纹理的类型。纹理可以有不同数量的通道和不同的位深度。然后,您可以像这样声明一个通用纹理类型:
class Texture<TChannels, TBPC>
where TChannels : INumOfChannels,new()
where TBPC : IBitsPerChannel,new()
INumOfChannels和IBitsPerChannel只是接口,可以为空。new()
约束
通过使用接口本身来防止创建具体的纹理类型。
对于不同的通道和不同的 BPC,您将创建从各自的基本接口扩展的空类型,例如:
class FourChannels : INumOfChannels {};
class ThreeChannels : INumOfChannels {};
class BitsPerChannel_24 : IBitsPerChannel {};
class BitsPerChannel_32 : IBitsPerChannel {};
使用它,您可以将通用方法限制为某些属性组合。如果您的方法应该只处理 4 通道和 32bpc 纹理:
void MyMethod<TChannels, TBPC>(Texture<TChannels, TBPC> foo)
where TChannels : FourChannels
where TBPC : BitsPerChannel_32
现在,每件好事也有阴暗面。你会怎么做这样的事情(写成伪代码)?
switch (NumOfChannelsAttribute)
{
case FourChannels:
// do something
break;
case ThreeChannels:
// do something else
break;
}
你不能,至少不能以简单的方式,因为“FourChannel”和“ThreeChannel”是类型,而不是整数值。
当然,您仍然可以使用if构造。为此,您需要在通用纹理类型中实现一个属性,该属性提供使用的属性:
class Texture<TChannels, TBPC> where TChannels : INumOfChannels,new() where TBPC : IBitsPerChannel,new()
{
public Type ChannelsAttribute
{
get { return typeof(TChannels); }
}
public Type BitsPerChannelAttribute
{
get { return typeof(TBPC); }
}
}
在if构造中,您可以按如下方式使用它:
var myTex = new Texture<FourChannels, BitsPerChannel_32>();
if (myTex.ChannelsAttribute == typeof(FourChannels))
{
... do something with 4 channels
}
else
{
... though luck, only 4 channels are supported...
}
最后一点和建议:
虽然这可能对您的问题有用,但使用这些“技巧”通常表明设计存在缺陷。我认为,如果您重新审视您在代码中所做的设计选择,那么这是值得投入的时间,因此您不需要依赖这样的拐杖。