【问题标题】:C# Dictionary of generic classesC# 泛型类字典
【发布时间】:2017-01-30 20:23:23
【问题描述】:

我是 C# 新手。我正在尝试在 C# 中实现一个字典,其 Java 等效项是:

HashMap<string, Variable<?>> dictionary

这是我正在尝试做的详细 Java 版本:Java how to manage user-defined variables

到目前为止,在 C# 中我有这样的东西:

interface IVariable { }

public class Variable<T> : IVariable
{
    public T myValue { get; set; }
}

Dictionary<string, IVariable> vars = new Dictionary<string, IVariable>();

然后我尝试这样做:

Variable<int> age = new Variable<int>();
age.myValue = 12;
vars.Add("age", age);
IVariable theVar;
if (vars.TryGetValue("age", out theVar) {
   Console.WriteLine("fetched age is " + theVar.myValue);
}

我在最后一行遇到了麻烦,因为编译器无法识别theVarmyValue 成员,因为它是IVariable

在这个简单的例子中,也许我可以将theVar 声明为Variable&lt;int&gt; 而不是IVariable,但我没有尝试过,因为它需要先验知识我从中获取的变量类型字典,我可能并不总是有这些知识。

我不介意myValue 是否是继承/抽象属性(如果有的话),因为每个变量都有一个名为myValue 的属性(每个变量的类型不同,但名称不同)。在这种情况下,我想我可以将IVariable 设为abstract class 而不是interface,但我仍然会遇到麻烦,要为myValue 类型添加什么。

我可以先用is 检查它的类型,然后使用astheVar 转换成一个东西吗?我不确定这是否可行,甚至可能。

我查看了这些帖子以获得指导(尤其是第二个):

Wildcard equivalent in C# generics

C# Generics: wildcards

但是,我的情况仍然与上面的第二个示例略有不同,因为该示例有一个返回 void 的抽象方法,而我希望我的变量返回非 void 泛型值。

感谢您的帮助。

【问题讨论】:

    标签: c# dictionary generics wildcard


    【解决方案1】:

    C# 有dynamic。你可以创建Dictionary&lt;string, dynamic&gt;

    或者你可以使用对象(boxing/unboxingDictionary&lt;string, object&gt;

    或者你可以得到generic type from class

    class MyClass<TDicValue>
    {
        Dictionary<strint, TDicValue> myDictionary;
    }
    

    【讨论】:

    • 不幸的是我不能使用动态,因为我使用的是 Unity 并且不支持动态。所以我尝试使用装箱/拆箱。我在下面发布了我的解决方案,请看一下,让我知道它是否有效。谢谢!
    • 我没有使用Unity,请自行尝试。您也可以使用来自类声明的泛型类型。
    • 对不起,我不是故意的,这听起来像是在要求您输入并为我测试!我说得不好。我的意思是,你能看看我的帖子,看看你对解决方案的看法吗?我确实将它输入 Unity 并对其进行了测试,它确实有效。但仅仅因为代码有效并不意味着它是防弹的。 :)
    【解决方案2】:

    我尝试使用装箱/拆箱并想出了这个解决方案。它似乎工作......到目前为止。不过好像不太安全。

    public interface Variable
    {
        object getValue();
        void setValue(object value);
        Type myType();
    }
    
    public class Variable<T>: Variable
    {
        private T myValue;
    
        public object getValue() 
        {
            return myValue;
        }
    
        public void setValue(object value)
        {
            myValue = (T)value;
        }
    
        public Type myType() { return myValue.GetType(); }
    }
    
        Dictionary<string, Variable> vars = new Dictionary<string, Variable>();
    
        Variable<int> age = new Variable<int>();
        age.setValue(21);
        vars.Add("age", age);
        Variable theAgeVar;
        vars.TryGetValue("age", out theAgeVar);
        Console.WriteLine("age = " + theAgeVar.getValue());
    
        Variable<double> height = new Variable<double>();
        height.setValue(5.9);
        Variable theHeightVar;
        vars.TryGetValue("age", out theHeightVar);
        Debug.Log("height = " + theHeightVar.getValue());
    

    打印出来:

    年龄 = 21

    高度 = 5.9

    我不喜欢的一件事是我必须将getValue() 的返回类型设为object。例如,如果我想让myValue(类型为T)实现IComparable,那么当装箱发生并且调用者收到object 时,此信息就会丢失。

    【讨论】:

      【解决方案3】:

      我遇到了同样的问题,我有 20 种略有不同的类型,我不得不继续使用字典。我想把它们整理成一个列表。

      问题是一样的,使用反射或字符串从列表中选择正确的类型缺乏提供返回类型的能力。 @skrilmps 的答案是正确的,但是如果没有很多(公吨)丑陋的杂乱代码,打包和拆包充其量是不可靠的。

      虽然 unity 在 2020 年确实支持动态,但这并不完全适用于我正在做的事情,除非我让一切动态安全并且这是乱码编码,不可扩展或可维护,听起来就像一场噩梦。

      我个人觉得,经过多年的努力学习,我还是一个不合格的程序员,但我的努力仍然没有提供有效的回报或值得注意的产品,所以我不能声称答案是我的,但在我对正确解决方案的研究中对于这个问题我发现了这个:https://www.youtube.com/watch?v=A7qwuFnyIpM

      在这里,他基本上说,如果您将接口添加到旨在用于各种不同列表的类似类中,则可以改为创建该类型接口的列表。我也假设是字典,然后您可以将实现此接口的任何类型的类添加到这个单一的接口类型定义列表中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-06-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-08-21
        • 1970-01-01
        • 2010-10-15
        • 1970-01-01
        相关资源
        最近更新 更多