简体   繁体   English

来自C背景,在C#中实现const引用数据表/结构的好方法是什么?

[英]Coming from a C background, what's a good way to implement const reference data tables/structures in C#?

I'll give a quick example of what I'm familiar with implementing using C . 我将给出一个简短的示例,说明我对使用C实现的熟悉程度。 The focus I think is on how the data can be used, not so much what I'm doing with it in the example :) 我认为重点在于如何使用数据,而不是我在示例中使用的数据:)

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);
}

So I'm looking for advice on how similar data tables, or reference data, are implemented in C#. 因此,我正在寻找有关如何在C#中实现类似数据表或参考数据的建议。 I'm getting the hang of the higher level side of things, but I haven't dealt with any table driven data methods yet. 我已经掌握了更高级的内容,但是我还没有处理任何表驱动的数据方法。

As an example, what I might be trying to do in C# is to have a combo box allowing selection from the description field, while the colour id and quantity might be used to update read-only boxes. 例如,我可能要在C#中尝试做的是创建一个组合框,允许从描述字段中进行选择,而颜色ID数量可能会用于更新只读框。

That's a really simple example, but if I can determine a good way to implement that, I can extrapolate that to what I'm actually doing. 这是一个非常简单的示例,但是如果我可以确定实现此目标的好方法,则可以将其推断为我的实际工作。

I'd use a ReadOnlyCollection<T> of an immutable class. 我会使用不可变类的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)
            });

This 这个

const my_data_t ref_data[] =
{
  {"Brown Bear", 0x88,   10},
  {"Blue Horse", 0x666,  42},
  {"Purple Cat", 123456, 50},
};

can be substituted with readonly modifier in C# , like 可以用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},
};

where ref_data (in this case) is something like 其中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
}

The same is valid for constant const char *description , use readonly . 这对于常量const char *description也有效,请使用readonly

I repeat, this is a by convention, as theoretically there is a, by the way, ways to change a data or trick access to it. 我再说一遍,这是惯例,因为从理论上讲,有一种更改数据或欺骗访问数据的方法。

There is no concept of constant pointer in C# , as pointers (in managed memory) constantly moved all arround, as Garbage Collector continuously shrinks (defrags) memory, in order to avoid memory fragmentation, which brings us a benefit of fast allocations. C#没有常量指针的概念,因为垃圾收集器不断缩小(碎片整理)内存以避免内存碎片,从而使指针(在托管内存中)不断移动,从而避免内存碎片,这给我们带来了快速分配的好处。

There is another option too (don't know if this is a suitable in your case or not), you can use unmanged access to the code, via unsafe modifier and keep all your C/C++ pointer stuff inside. 还有另一种选择(不知道这是否适合您),您可以通过unsafe修饰符对代码进行无管理的访问,并将所有C/C++指针保留在其中。 In this way, you say to Grabage Collector: "wait, I know what I'm doing", so the all memory management has to be handled by you (inside that unmanaged code) as if you write ordinary C/C++ code. 这样,您对Grabage Collector说:“等等,我知道我在做什么”,因此所有内存管理都必须由您(在非托管代码中)处理,就像编写普通C/C++代码一样。

I'm posting this answer in response to your request that I elaborate on my comment in Joe's answer. 我正在发布此答案,以回应您对我在Joe答案中的评论进行详细说明的请求。

First point: if you need my_data_t to be a struct for whatever reason, C# does support those. 第一点:如果出于某种原因需要my_data_t作为结构,C#会支持这些结构。 You don't have to upgrade it to a class, as Joe did, unless you want to. 除非您愿意,否则不必像Joe一样将其升级为课程。

public struct MyData
{
    public string Description;
    public uint ColourID;
    public uint Quantity;
} 

This is a mutable struct. 这是一个可变的结构。 Given an instance of this struct, I can modify its values if I so choose. 给定该结构的一个实例,可以选择修改它的值。 Most people would say that mutable structs are evil. 大多数人会说可变结构是邪恶的。 As a game developer, I would say that mutable structs are enormously important , but also dangerous . 作为游戏开发人员,我想说可变结构非常重要 ,但也很危险

The mutable fields and properties of any object can be initialized using the object initializer syntax, which is probably most analogous to what you're doing in C: 可以使用对象初始值设定项语法来初始化任何对象的可变字段和属性,这可能与您在C语言中所做的最相似:

MyData x = { Description = "Brown Bear", ColourID = 0x88, Quantity = 10 };

Personally I think this is a bit unwieldy, especially for large structs, but it is available if you want to use it. 我个人认为这有点笨拙,尤其是对于大型结构,但是如果您想使用它就可以使用。

You can change the struct to be immutable by adding readonly modifiers to its fields: 您可以通过向其字段添加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;
} 

Note that readonly only prevents the object references from being changed. 请注意, readonly仅防止更改对象引用。 It does not prevent the objects themselves from being mutated, if they're mutable. 如果它们是可变的,它不会阻止对象本身的突变。

Note also that I've also added a constructor. 还要注意,我还添加了一个构造函数。 This is because readonly fields can only be set in a static initializer or inside of the object's constructor (barring some trickery). 这是因为readonly字段只能在静态初始化程序中或在对象的构造函数内部设置(除非有一些技巧)。 Here, you would initialize a new instance of MyData as in Joe's answer: 在这里,您将按照Joe的回答初始化MyData的新实例:

MyData x = new MyData("Brown Bear", 0x88, 10);

Second point: constness, or the lack thereof. 第二点:保持不变或缺乏稳定。 C# doesn't support C-style constness because C-style constness is broken . C#不支持C样式常量,因为C样式常量已损坏 Eric Lippert, formerly a developer on the C# language team at Microsoft, elaborated on that point here . 埃里克利珀,以前在C#语言的团队在微软开发人员,详细阐述了这一点这里

It is far better, I think, not to worry about emulating C-style constness unless you really, really, really have a good reason to. 我认为,除非您真的,真的,真的有充分的理由这么做,否则不要担心仿效C样式的常数性。 Constness is ultimately a way to prevent your code from being tampered with by the malicious or the ignorant. 常量最终是防止您的代码被恶意或无知者篡改的一种方法。 The malicious are going to be able to mutate your data whether you like it or not--in C, and in C#--and we have a much better tool for protecting yourself from the ignorance of others: encapsulation! 无论您是否喜欢,无论是在C中还是在C#中,恶意软件都将能够变异您的数据,并且我们有一个更好的工具来保护自己免受他人的无知:封装!

Wrap the functionality that uses this table inside of a class, make the table a private member of that class, and then don't mutate it . 将使用该表的功能包装到类中,使该表成为该类的私有成员,然后不要对其进行突变 If at some point you do need to expose that table to the outside world, then you can use ReadOnlyCollection as Joe suggested: 如果确实需要将该表暴露给外界, 可以按照Joe的建议使用ReadOnlyCollection

public static readonly ReadOnlyCollection<MyData> ReferenceTable = new ReadOnlyCollection<MyData>(new []
{
    new MyData(/* whatever */),
    new MyData(/* whatever */),
    new MyData(/* whatever */),
});

ReadOnlyCollection is just a thin wrapper around some other collection, in this case, your data table. ReadOnlyCollection只是其他一些集合(在本例中为数据表)的精简包装。 It can wrap any object which implements the IList<T> interface, which includes arrays and several of the built-in collections. 它可以包装实现IList<T>接口的任何对象,该接口包括数组和一些内置集合。

One more note: in one of your comments you mentioned that one of the reasons for declaring the table const in C is because it influences where the object is allocated in memory. 还有一点需要注意:在您的评论之一中,您提到了在C中声明表const的原因之一是因为它影响对象在内存中的分配位置。 This is not the case here. 这里不是这种情况。 In the example above, RefData will be declared on the managed heap, because it's an array, and arrays are reference types. 在上面的示例中, RefData将在托管堆上声明,因为它是一个数组,并且数组是引用类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 什么是处理从MySQL和C#返回的数据的好方法? - What is a good way to handle returned data from MySQL and C#? 这个项目在 C 中的等效脚手架是什么(来自 C#)? - What's the equivalent scaffholding of this project in C (coming from C#)? 在C#中实现REST API的好方法 - A good way to implement a REST API in C# 在C#中捕获StackOverflow异常的一般方法是什么? - What's a good general way of catching a StackOverflow exception in C#? 在C#中编写批处理脚本的好方法是什么? - What's a good way to write batch scripts in C#? 在C#项目中存储不变变量的好方法是什么? - What's a good way to store unchanging variables in a C# project? 在C#中,什么是显示可缩放,可平移视频的好方法? - In C#, what's a good way for displaying zoomable, pannable video? 从 2 个表中检索数据以填充在 C# 中包含另一个对象列表的对象列表的最佳方法是什么? - What's the best way to retrieve data from 2 tables for filling a list of objects that has another list of objects inside it in C#? C#数据结构 - C# data structures 在C#Winforms应用程序中从命令提示符收集数据的好方法是什么? - What would be a good way to collect data from the command prompt in a C# Winforms Application?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM