具有不同值类型的List<T>

7

C#。 我有一个类:

public class SQLValue<T> 
{ 
    public string nam { get; set; } 
    public string typ { get; set; } 
    public T val      { get; set; } 
}

现在我想创建一个……
List<SQLValue> lst = List<SQLValue>();

然后像这样向其中添加元素:

lst.Add(new List<SQLValue>(nam = "PlayerName", typ = "string", val = "Bot1"));
lst.Add(new List<SQLValue>(nam = "Ally", typ = "bool", val = true));
lst.Add(new List<SQLValue>(nam = "Levl", typ = "int",  val = 2));

我想要一个包含不同类型值val的类列表,这是可能的吗?


1
尝试使用 dynamic 作为泛型类型。 - vikscool
1
lst 是如何使用的? - Spotted
@Spotted 这是一个非常重要的问题。我在想,也许 OP 想要模仿从 SqlDataReader.Item[] 中获取类型和值的方式,但还想确定一下。 - John Wu
你想要一个可以以某种方式为 List<T1, T2> 的东西吗? - AustinWBryan
另外,每种类型的项目数量总是相同的吗?比如如果有5个int,那么也会有5个string和5个T吗? - AustinWBryan
3个回答

6

你不能这样做。

必须使用某些基本类型。如果你只是想存储SQLValue<T>实例,那么你总是可以使用List<object>

但是,假设您想根据namtyp属性处理列表项,则在此处所能做的就是提取一些基类/接口:

public interface ISQLValue
{
    public string nam { get; set; } 
    public string typ { get; set; } 
    public object val { get; set; }
}

将其在SQLValue<T>中实现:

public class SQLValue<T> : ISQLValue
{ 
    public string nam { get; set; } 
    public string typ { get; set; } 

    public T val { get; set; } 

    object ISQLValue.val 
    {  
        get { return this.val; }
        set { this.val = (T)value; }
    }
}

使用 List<ISQLValue> 存储实例并对它们进行处理:

var sqlValues = new List<ISQLValue>
{
    new SQLValue<string> { nam="PlayerName", typ="string", val="Bot1" }
    new SQLValue<bool> { nam="Ally", typ="bool", val=true }
    new SQLValue<int> { nam="Levl", typ="int", val=2 }
};

foreach (var value in sqlValues)
{
    Console.WriteLine($"nam = {value.name}, typ = {value.typ}, val = {value.val}");
}

也就是说,在某些批量处理的情况下,将使用ISQLValue。但是如果您知道特定ISQLValueT,则可以将其强制转换为SQLValue<T>并使用T val而不是object val


1

不行,因为泛型最终会转换成单独的类型。

当一个泛型类型第一次被构造时,如果使用值类型作为参数,运行时会创建一个专门化的泛型类型,并在MSIL中替换适当位置的提供的参数或参数。 每个唯一的值类型用作参数时,都会创建一个专门化的泛型类型

参考: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generics-in-the-run-time

所以,SQLValue<int>SQLValue<bool>实际上是两种不同的类型。因此,您不能使用以下方式创建List<T>

var lst = new List<SQLValue>();

相反,您还需要为 SQLValue 指定类型 T 。 因此,像这样的内容将被允许,
var lst = new List<SQLValue<bool>>();

或者,
var lst = new List<SQLValue<int>>();

此外,你代码中添加元素到列表的语法是不正确的。例如,如果你正在使用一个列表,
var lst = new List<SQLValue<bool>>();

你可以使用以下方法向其添加值:

lst.Add(new SQLValue<bool> {  nam="Ally", typ="bool", val=true });

或者,通过构造函数,如果您已经定义了一个

lst.Add(new SQLValue<bool> ("Ally", "bool", true ));

构造函数可以是:

public SQLValue(string nam, string typ, T val )
{
    this.nam = nam;
    this.typ = typ;
    this.val = val;
}

1
你可以创建自己的类,来保存所有这些信息:
class MyClass
{
    public string Name { get; set; }
    public Type PropType { get; set; }
    public object Value { get; set; }
}

然后你可以向其中添加项目:
List<MyClass> list = new List<MyClass>()
{
    new MyClass(){ Name = "name1", PropType = typeof(string), Value = "asdasd" },
    new MyClass(){ Name = "name2", PropType = typeof(bool), Value = true },
    new MyClass(){ Name = "name3", PropType = typeof(int), Value = 11 },

};

然后可以像这样使用它的例子:
foreach (var item in list)
{
    switch (Type.GetTypeCode(item.PropType))
    {
        case TypeCode.String:
            break;
        case TypeCode.Int32:
            break;
        case TypeCode.Boolean:
            break;
        default:
            throw new NotSupportedException();
    }
}

尽管这个解决方案看起来不太好,但我认为这是这个问题的适当答案。我很欣赏C#拥有更复杂的工具,比如dynamic和泛型,但有时你只需要一个对象!(话虽如此,我认为导致OP提出问题的设计是可疑的。) - John Wu
我希望OP能提供一些评论或更多细节,以了解他实际想要实现什么,因为这有点XY问题。无论如何,我尝试给他一些替代想法,也许他会自己注意到他的问题。 - SᴇM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接