通用对象的通用列表

Dan*_*zyk 20 c# generics generic-list

假设我有一个表示数据字段的对象,该对象需要以下属性:Name,Type,Value,Length.这是对象:

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; }
}  
Run Code Online (Sandbox Code Playgroud)

我使用了泛型,因为我想强制代码的用户只能分配某种类型的值.
现在的问题是我想创建一个字段列表.
如果我像那样创建列表,List<Field<object>>我们可以将任何值分配给列表中的给定字段,当我们查询Type时,我们得到'object'.
事情是 - 在那个列表上我可能想要几个字段持有字符串,很少持有整数,日期,甚至自定义对象反过来将有一个字段列表......
泛型是一个很好的解决方案吗?如果是的话,我将如何实施呢?如果没有,有什么更好的方法?

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

List<Field<object>> lst = new List<Field<object>>();
lst.Add(new Field<string>());
lst.Add(new Field<int>());
lst.Add(new Field<SomeObjectFromMyApp>());
Run Code Online (Sandbox Code Playgroud)

2.稍后我将不得不在循环中自动查询这些对象及其属性,类似于:

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

Dav*_*rno 18

是的,仿制药是一个不错的选择.实现类型安全的关键(并且使用Type属性标识类型是在列表和Field<T>类之间添加抽象.

Field<T>实现接口IField.此界面不需要任何成员.

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

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

然后再读取这些值

foreach(var field in list)
{
    var type = field.Type;
    ....
}
Run Code Online (Sandbox Code Playgroud)

  • @Wish,它们包含数据; 没有强制转换就无法访问该数据.三年后看了这个答案,我不明白为什么会被投票赞成.`var type = field.Type;`行是无意义的,不会编译. (3认同)
  • @DavidArno 2 年后,我偶然发现了这个问题,我注意到 `var type = field.Type` 不会编译,但是,有一个简单的修复方法。你可以简单地使用`dynamic type = field.Type`,一切都很好。所以也许将此添加到答案中可以帮助某人。谢谢你。 (3认同)
  • 这将解决创建列表的问题,但它不会解决读取值的问题,因为现在我必须转换为适当的 Field&lt;_type_&gt; ,而且我无法知道 \_type\_那时候... (2认同)

Vah*_*hiD 13

我建议你定义一个接口,Field实现那个接口

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; }
}
Run Code Online (Sandbox Code Playgroud)

所以你可以写这个代码:

var list = new List<IField>();
Run Code Online (Sandbox Code Playgroud)

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

  • 他们之间只有4分钟.如果你像我一样慢,你可能没有注意到另一个答案. (10认同)
  • 是的,我没有注意到其他答案:) (2认同)

小智 5

正如一些评论者已经提到的,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

然后您可以检查 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}");
    }
}
Run Code Online (Sandbox Code Playgroud)

该代码产生以下输出:

// 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
Run Code Online (Sandbox Code Playgroud)