在C#中是否有一种理智的方式来实现以下构造(伪代码):
void Method(MyClass<Attribute1, Attribute2, ...> foo)
{
// here I am guaranteed that foo has the specified attributes
}
例如,Attribute*
是枚举值,这样只有实例化了方法所需属性的MyClass
实例才能传递给方法(否则无法编译)? / p>
我尝试查看泛型,因为我知道C ++模板可以使它工作,所以它似乎是一个逻辑起点,但我无法让它优雅地工作(我尝试使用接口来约束参数的类型)时尚,但它非常笨重,坦率地说无法使用,因为我至少有4个属性。)
我想这样做是为了避免在每种方法的开头都进行大量烦人的检查。我正在进行DirectX 11图形开发,所以我受到API的限制,这使得以这种“类型安全”方式传递对象变得特别容易(在DirectX中,每个资源都有一个包含信息的大型“描述”结构关于资源可以做什么和不能做什么,是和不是等等。并且解析起来很乏味且容易出错,因此我试图围绕它编写一个包装器,以便我和我的用户方便。)
我也不能为每种情况都有不同的类类型,因为有很多组合,所以这似乎是编写这样的代码最舒服的方式,我希望C#能够实现这一点。
我确定这种语言功能有一个名称(如果您知道它请告诉我,我会用谷歌搜索,但是当您不知道正确的关键字时,这很难搜索。 ..)
答案 0 :(得分:2)
.NET中的泛型类型参数必须是类型本身。您不能仅创建特定于Generic类型参数的特定值的泛型类型/方法。
如果您不想或不能创建表示您希望限制方法的属性值的类型,则必须在方法中进行完整性检查,以确保在提供的“foo”中使用正确的属性值“对象。
使用特定类型作为特定属性值的表示可能是您询问的问题的答案,但它的缺点是不支持switch-case语句(请参见下文)。还请在我的答案结尾处阅读最后的说明。
说,你想要一个代表纹理的类型。纹理可以具有不同数量的通道和不同的位深度。然后,您可以声明这样的通用纹理类型:
class Texture<TChannels, TBPC>
where TChannels : INumOfChannels,new()
where TBPC : IBitsPerChannel,new()
INumOfChannels 和 IBitsPerChannel 只是接口,可以为空。
new()约束通过使用接口本身来阻止创建具体的Texture类型。
对于不同的通道和不同的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...
}
最后的说明和建议:
虽然这可能对您的问题有用,但采用这种“技巧”通常表明设计存在缺陷。我认为如果你重新审视你在代码中做出的设计选择,那么这是一个很好的投入时间,所以你不需要依赖这样的拐杖。
答案 1 :(得分:1)
C#没有这样的功能。您提到您已尝试使用接口,但未指定方式。我建议您尝试使用它们的方法是使用具有多个约束的泛型,例如
void Method(T foo) where T : IAttribute1, IAttribute2, IAttribute3, IAttribute4
{
}
假设一个这样的属性类是ICpuMappable,那么你可以用Method1
约束可以用于的类型:
void Method1(T foo) where T : ICpuMappable
{
}
你可以知道传递给foo
的任何Method1
都是CPU可映射的。
你可能最终会得到很多接口,但是由于许多接口被视为“标志”,因此它们不应该太难维护。