簡體   English   中英

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()

INumOfChannelsIBitsPerChannel只是接口,可以為空。
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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM