![](/img/trans.png)
[英]Will an attribute instance be created for each instance of a class in C#?
[英]C# class instance attribute mechanism
C#中是否有一種明智的方法來實現以下構造(以偽代碼形式):
void Method(MyClass<Attribute1, Attribute2, ...> foo)
{
// here I am guaranteed that foo has the specified attributes
}
例如,在Attribute*
是枚舉值的情況下,只有用該方法所需的屬性實例化的MyClass
實例才能傳遞給該方法(否則無法編譯)?
我嘗試查看泛型,因為我知道C ++模板可以完成此工作,因此這似乎是一個合理的起點,但是我無法使其優雅地工作(我嘗試使用接口以這種方式約束參數的類型,但是由於我至少有4個屬性,因此體積非常大,並且坦率地說無法使用)。
我這樣做是為了避免在每種方法開始時進行許多煩人的檢查。 我正在進行DirectX 11圖形開發,因此受到API的限制,該API並不特別容易以這種“類型安全”的方式傳遞對象(在DirectX中,每個資源都具有包含信息的大型“描述”結構。關於資源可以做什么和不能做什么,是和不是的等等。並且解析起來很繁瑣且容易出錯,因此為了我和我的用戶的方便,我試圖圍繞它編寫一個包裝器。
我也不能在每種情況下都有不同的類類型,因為有很多組合,所以這似乎是編寫這樣的代碼的最舒適的方式,我希望C#能夠做到這一點。
我敢肯定這種語言功能有一個名字(如果知道的話,請告訴我,我會用Google搜索的,但是當您不知道合適的關鍵字時,這種搜索就很難了...)
.NET中的通用類型參數必須是類型本身。 您不能創建僅特定於通用類型參數的特定值的通用類型/方法。
如果您不希望或無法創建表示要限制方法使用的屬性值的類型,則必須對方法進行完整性檢查,以確保在提供的“ 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...
}
最后的注意事項和建議:
盡管這可能會解決您的問題,但訴諸此類“技巧”通常表明設計存在缺陷。 我認為,如果您重新查看在代碼中所做的設計選擇,這將是一個投入充分的時間,因此您無需依賴這樣的拐杖。
C#沒有這種功能。 您提到您嘗試使用接口,但未指定如何使用。 我建議您嘗試使用它們的方式是使用具有多個約束的泛型,例如
void Method(T foo) where T : IAttribute1, IAttribute2, IAttribute3, IAttribute4
{
}
假設一個這樣的屬性類是ICpuMappable,然后可以使用以下方法約束可以與Method1
一起使用的類型:
void Method1(T foo) where T : ICpuMappable
{
}
並且您可以知道傳遞給Method1
所有foo
都是CPU可映射的。
您可能最終會擁有很多接口,但是由於許多接口都將被視為“標志”,因此它們的維護應該不會太困難。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.