3

我有一种情况,我需要一个类,该类需要包含有关在运行时变化的事物的信息,例如:

class Info<T>
{
    public T Max { get; set; }
    public T Min { get; set; }
    public T DefaultValue { get; set; }
    public T Step { get; set; }
    // Some other stuff
}

我必须将此类的许多实例存储在字典中,但问题是要使用字典,我必须声明一种类型,例如

Dictionary<string, Info<int>> dict = new Dictionary<string, Info<int>>();

在这种情况下,我无法添加其他类型的信息,例如Info<double>. 我想要类似的东西,我在以下情况下删除了通用版本。

 {"Price", new Info{Min=100,Max=1000,DefaultValue=200,Step=50}}
 {"Adv", new Info{Min=10.50,Max=500.50,DefaultValue=20.50,Step=1.5}}
 {"Answer", new Info{Min=false,Max=false,DefaultValue=false,Step=false}}

我可以用Dictionary<string, Object> dict = new Dictionary<string, Object>();

但是当我拿回 dict 项目时,我不知道那是什么类型,我也需要知道类型,例如Price它是 int 而对于 Adv 它是 double ,我如何在运行时知道它?

实际上我想创建一个验证器(我正在使用.Net Compact Framework 3.5/如果它存在则不能使用任何内置系统)例如如果我有一个像下面这样的类..

class Demo
{
    public int Price { get; set; }
    public float Adv { get; set; }

    public static bool Validate(Demo d)
    {
        List<string> err = new List<string>();
        // here I have to get Info about the Price
        // from dictionary, it can be any storage
        Info priceInfo = GetPriceInfo("Price");
        if (d.Price < priceInfo.Min)
        {
            d.Price = priceInfo.Min;
            err.Add("price is lower than Min Price");
        }
        if (d.Price > priceInfo.Max)
        {
            d.Price = priceInfo.Max;
            err.Add("price is above than Max Price");
        }
        // need to do similar for all kinds of properties in the class  
    }
}

所以想法是将验证信息存储在一个地方(在字典或其他地方),然后在验证时使用该信息,我还想知道我是否可以以更好的方式设计上述场景?

也许有更好的方法可以做到这一点,请问有什么指导方针吗?

4

4 回答 4

4

您可以使用非泛型基类:

public abstract class Info {
}

public class Info<T> : Info {
}

现在所有不同的泛型类型都继承自同一个基类型,因此您可以在字典中使用它:

Dictionary<string, Info> dict = new Dictionary<string, Info>();

您可以在基类中定义接口不依赖于泛型类型的属性和方法,并在泛型类中实现它们。这样您就可以在不指定泛型类型的情况下使用它们。

对于需要类型的方法,您需要每种类型的特定代码。您可以使用isandas运算符来检查类型:

Info<int> info = dict[name] as Info<int>;
if (info != null) {
  int max = info.Max;
}
于 2013-02-06T21:18:03.703 回答
1

您可以从 Microsoft 获取并模仿IEnumerable接口并创建一个.Cast<T>? dynamic但是,除非您想进入(仅限 4.0+)或反射,否则必须有人知道您的类型。两者都是有代价的。也许您需要重新考虑您的设计?

于 2013-02-06T21:14:22.250 回答
0

Keith Nicholas 是对的——如果您希望您的字典支持多种类型,您将需要一个接口,但它需要是一个通用接口。

尝试这样的事情(警告:未经测试的代码):

interface IInfo<T>
{
    T Max { get; set; }
    T Min { get; set; }
    T DefaultValue { get; set; }
    T Step { get; set; }
}

Dictionary<string, IInfo> dict = new Dictionary<string, IInfo>();

class AnswerInfo : IInfo<bool> { }
class PriceInfo : IInfo<int> { }
class AdvInfo : IInfo<double> { }

dict["Answer"] = new AnswerInfo() { Min = false, Max = false, DefaultValue = false, Step = false };
dict["Price"] = new PriceInfo() { Min = 100, Max = 1000, DefaultValue = 200, Step = 50 };
dict["Adv"] = new AdvInfo() { Min = 10.50, Max = 500.50, DefaultValue = 20.50 Step = 1.5 };
于 2013-02-06T21:31:42.867 回答
0

使用对象字典(或某些基类),您将有多种选择来获取数据(通常,涉及从要使用的通用基类进行的某种继承,其属性如下所述)。

  1. 使用枚举来表示类型,然后你可以有某种开关/案例。(很容易做到,不是很 C#ish。)
  2. 使用类似于 VARIANT 的东西。变体是既提供存储的信息又提供存储的值的类型,可以是任何基本类型,如字符串、int、float。(在 C# 中并不存在,您可以从此处的Variant Type in C#的答案中看到。)
  3. 您还可以在运行时测试对象的类型以找出您拥有的对象类型,然后根据其类型进行转换并处理其内容。(几种方法..可能必须使用反射,首先看看这里:获取对象类型并相应地分配值。)
  4. 实际上,您还可以尝试以某种方式抽象您想要对每个对象执行的操作,然后调用该函数。类似于命令模式的东西。(命令模式:如何将参数传递给命令?

可能还有很多。:)

于 2013-02-06T21:50:15.027 回答