C# 通用对象的通用列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/19490819/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 15:07:49  来源:igfitidea点击:

Generic list of generic objects

c#genericsgeneric-list

提问by Daniel Gruszczyk

Let's say I have an object that represents a field of data, that object needs the following properties: Name, Type, Value, Length. Here is the object:

假设我有一个表示数据字段的对象,该对象需要以下属性:名称、类型、值、长度。这是对象:

class Field<T>
{
    public string Name { get; set; }
    public Type Type
    {
        get
        {
            return typeof(T);
        }
    }
    public int Length { get; set; }
    public T Value { get; set; }
}  

I have used generics, because I want to force the user of the code to only be able to assign a Value of certain Type.
Now the problem is when I want to create a list of fields.
If I create the list like List<Field<object>>then we can assign any Value to a given Field on the list, and when we query for Type, we get 'object'.
The thing is - on that list I might want few fields holding strings, few holding ints, dates, and even custom objects that in turn will have a list of Fields...
Is the Generics a good solution for something like that? If yes, how would I go about implementing it? If not, what is a better way?

我使用了泛型,因为我想强制代码的用户只能分配某个类型的值。
现在的问题是当我想创建一个字段列表时。
如果我像这样创建列表,List<Field<object>>我们可以为列表中的给定字段分配任何值,当我们查询类型时,我们会得到“对象”。
问题是 - 在该列表中,我可能想要很少的字段保存字符串,很少保存整数,日期,甚至自定义对象,而这些自定义对象又将具有字段列表......
泛型是解决此类问题的好方法吗?如果是,我将如何实施它?如果没有,什么是更好的方法?

---EDIT---
Just to add some more background:
1. I might want a list of fields, and each field will hold different data type, like so :

---编辑---
只是为了添加更多背景:
1. 我可能想要一个字段列表,每个字段将包含不同的数据类型,如下所示:

List<Field<object>> lst = new List<Field<object>>();
lst.Add(new Field<string>());
lst.Add(new Field<int>());
lst.Add(new Field<SomeObjectFromMyApp>());

2. Later on I will have to query these objects, and their attributes automaticaly in a loop, something like that:

2.稍后我将不得不在循环中自动查询这些对象及其属性,如下所示:

foreach(Field<object> fld in lst)
{
    Type t = fld.Type;
    //do some other stuff
}

采纳答案by David Arno

Yes, generics is a good choice. The key to achieving type-safety (and being identify the type with the Typeproperty is to add an abstraction between the list and Field<T>class.

是的,泛型是一个不错的选择。实现类型安全(并通过Type属性识别类型)的关键是在列表和Field<T>类之间添加抽象。

Have Field<T>implement the interface IField. This interface doesn't need any members.

Field<T>实现接口IField。这个接口不需要任何成员。

Then declare your list as being List<IField>.

然后将您的列表声明为List<IField>.

That way you constrain the list to only contain fields, but each field can be of a different type.

这样您就可以将列表限制为仅包含字段,但每个字段可以是不同的类型。

To then read the values later, just do

要稍后读取值,只需执行

foreach(var field in list)
{
    var type = field.Type;
    ....
}

回答by VahiD

I suggest you to define an interface and Field<T>implements that interface

我建议您定义一个接口并Field<T>实现该接口

public interface IField
{

}

public class Field<T> : IField
{
    public string Name { get; set; }
    public Type Type
    {
        get
        {
            return typeof(T);
        }
    }
    public int Length { get; set; }
    public T Value { get; set; }
}

so you can write this code:

所以你可以写这个代码:

var list = new List<IField>();

now this list can contain any object of type Field<T>

现在这个列表可以包含任何类型的对象 Field<T>

回答by Michael Trapp

As a few commenters already mentioned, you cannot access the Typeproperty if you create an empty Interface, so I would rather do:

正如一些评论者已经提到的,Type如果您创建一个空的接口,您将无法访问该属性,所以我宁愿这样做:

public interface IField
{
    Type Type { get; }

    string Name { get; set; }

    int Length { get; set; }
}

public class Field<T> : IField
{
    public string Name { get; set; }

    Type IField.Type => typeof(T);

    public int Length { get; set; }

    public T Value { get; set; }

    public override string ToString()
    {
        return Value.ToString();
    }
}

Then you can check of which datatype the value property is and cast the object to the right type:

然后您可以检查 value 属性是哪种数据类型并将对象强制转换为正确的类型:

class Program
{
    static void Main(string[] args)
    {
        var fieldList = new List<IField>()
        {
            new Field<string>()
            {
                Value = "Hello World!", 
                Length = 12, 
                Name = "A string"
            },
            new Field<int>()
            {
                Value = 4711,
                Length = sizeof(int),
                Name = "An integer value"
            },
            new Field<double>()
            {
                Value = 2.4,
                Length = sizeof(double),
                Name = "A double value"
            },
        };

        foreach (var field in fieldList)
        {
            if (field.Type == typeof(string))
            {
                PrintField(field, "String value:");
            }
            else if (field.Type == typeof(int))
            {
                PrintField(field, "Integer value:");
            }
            else if (field.Type == typeof(double))
            {
                PrintField(field, "Double value:");
            }
        }
    }

    static void PrintField(IField field, string info)
    {
        Debug.WriteLine(info);
        Debug.WriteLine($"\tName: {field.Name}, Length: {field.Length}, Value: {field}");
    }
}

The code produces the following output:

该代码产生以下输出:

// String value:
//  Name: A string, Length: 12, Value: Hello World!
// Integer value:
//     Name: An integer value, Length: 4, Value: 4711
// Double value:
//     Name: A double value, Length: 8, Value: 2,4