[英]Coming from a C background, what's a good way to implement const reference data tables/structures in C#?
我將給出一個簡短的示例,說明我對使用C實現的熟悉程度。 我認為重點在於如何使用數據,而不是我在示例中使用的數據:)
typedef struct
{
const char *description;
uint32_t colour_id;
uint32_t quantity;
} my_data_t;
const my_data_t ref_data[] =
{
{"Brown Bear", 0x88, 10},
{"Blue Horse", 0x666, 42},
{"Purple Cat", 123456, 50},
};
void show_animals( void )
{
my_data_t *ptr;
ptr = &ref_data[2];
console_write("Animal: %s, Colour: 0x%8X, Num: %d",
ptr->description,
ptr->colour_id,
ptr->quantity);
}
因此,我正在尋找有關如何在C#中實現類似數據表或參考數據的建議。 我已經掌握了更高級的內容,但是我還沒有處理任何表驅動的數據方法。
例如,我可能要在C#中嘗試做的是創建一個組合框,允許從描述字段中進行選擇,而顏色ID和數量可能會用於更新只讀框。
這是一個非常簡單的示例,但是如果我可以確定實現此目標的好方法,則可以將其推斷為我的實際工作。
我會使用不可變類的ReadOnlyCollection<T>
。
public class MyData
{
public MyData(string description, int colorId, int quantity)
{
Description = description;
ColorId = colorId;
Quantity = quantity;
}
public string Description {get; private set; }
public int ColorId {get; private set; }
public int Quantity {get; private set; }
}
...
public static readonly ReadOnlyCollection<MyData> refData =
new ReadOnlyCollection<MyData>(
new [] {
new MyData("Brown Bear", 0x88, 10),
new MyData("Blue Horse", 0x666, 42),
new MyData("Purple Cat", 123456, 50)
});
這個
const my_data_t ref_data[] =
{
{"Brown Bear", 0x88, 10},
{"Blue Horse", 0x666, 42},
{"Purple Cat", 123456, 50},
};
可以用C#
readonly
修飾符替換,例如
//INITIALIZED ONES AND NEVER CHANGED, BY CONVENTION
public static readonly ref_data[] my_data_t = new ref_data[] =
{
new ref_data{Animal = "Brown Bear", Code = 0x88, Index = 10},
new ref_data{Animal = "Blue Horse", Code = 0x666, Index = 42},
new ref_data{Animal = "Purple Cat", Code = 123456, index = 50},
};
其中ref_data
(在這種情況下)類似於
public class ref_data
{
public string Animal {get;set;}
public int Code {get;set;} //GUESS, PUT APPROPRIATE NAME
public int Index {get;set;} //GUESS, PUT APPROPRIATE NAME
}
這對於常量const char *description
也有效,請使用readonly
。
我再說一遍,這是慣例,因為從理論上講,有一種更改數據或欺騙訪問數據的方法。
C#
沒有常量指針的概念,因為垃圾收集器不斷縮小(碎片整理)內存以避免內存碎片,從而使指針(在托管內存中)不斷移動,從而避免內存碎片,這給我們帶來了快速分配的好處。
還有另一種選擇(不知道這是否適合您),您可以通過unsafe
修飾符對代碼進行無管理的訪問,並將所有C/C++
指針保留在其中。 這樣,您對Grabage Collector說:“等等,我知道我在做什么”,因此所有內存管理都必須由您(在非托管代碼中)處理,就像編寫普通C/C++
代碼一樣。
我正在發布此答案,以回應您對我在Joe答案中的評論進行詳細說明的請求。
第一點:如果出於某種原因需要my_data_t
作為結構,C#會支持這些結構。 除非您願意,否則不必像Joe一樣將其升級為課程。
public struct MyData
{
public string Description;
public uint ColourID;
public uint Quantity;
}
這是一個可變的結構。 給定該結構的一個實例,可以選擇修改它的值。 大多數人會說可變結構是邪惡的。 作為游戲開發人員,我想說可變結構非常重要 ,但也很危險 。
可以使用對象初始值設定項語法來初始化任何對象的可變字段和屬性,這可能與您在C語言中所做的最相似:
MyData x = { Description = "Brown Bear", ColourID = 0x88, Quantity = 10 };
我個人認為這有點笨拙,尤其是對於大型結構,但是如果您想使用它就可以使用。
您可以通過向其字段添加readonly
修飾符來將結構更改為不可變的:
public struct MyData
{
public MyData(string description, uint colourID, uint quantity)
{
this.Description = description;
this.ColourID = colourID;
this.Quantity = quantity;
}
public readonly string Description;
public readonly uint ColourID;
public readonly uint Quantity;
}
請注意, readonly
僅防止更改對象引用。 如果它們是可變的,它不會阻止對象本身的突變。
還要注意,我還添加了一個構造函數。 這是因為readonly
字段只能在靜態初始化程序中或在對象的構造函數內部設置(除非有一些技巧)。 在這里,您將按照Joe的回答初始化MyData
的新實例:
MyData x = new MyData("Brown Bear", 0x88, 10);
第二點:保持不變或缺乏穩定。 C#不支持C樣式常量,因為C樣式常量已損壞 。 埃里克利珀,以前在C#語言的團隊在微軟開發人員,詳細闡述了這一點這里 。
我認為,除非您真的,真的,真的有充分的理由這么做,否則不要擔心仿效C樣式的常數性。 常量最終是防止您的代碼被惡意或無知者篡改的一種方法。 無論您是否喜歡,無論是在C中還是在C#中,惡意軟件都將能夠變異您的數據,並且我們有一個更好的工具來保護自己免受他人的無知:封裝!
將使用該表的功能包裝到類中,使該表成為該類的私有成員,然后不要對其進行突變 。 如果確實需要將該表暴露給外界, 則可以按照Joe的建議使用ReadOnlyCollection
:
public static readonly ReadOnlyCollection<MyData> ReferenceTable = new ReadOnlyCollection<MyData>(new []
{
new MyData(/* whatever */),
new MyData(/* whatever */),
new MyData(/* whatever */),
});
ReadOnlyCollection
只是其他一些集合(在本例中為數據表)的精簡包裝。 它可以包裝實現IList<T>
接口的任何對象,該接口包括數組和一些內置集合。
還有一點需要注意:在您的評論之一中,您提到了在C中聲明表const
的原因之一是因為它影響對象在內存中的分配位置。 這里不是這種情況。 在上面的示例中, RefData
將在托管堆上聲明,因為它是一個數組,並且數組是引用類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.