Typed<祝辞/无类型的设计

本文关键字:类型 祝辞 Typed | 更新日期: 2023-09-27 17:48:56

我有一个(现有的)类型类:

Items<T>
    T Value { get; }

T可以是双精度、字符串或整型。

然后我有一个类,它必须保存几个item的实例。在该类的单个实例中,T总是相同的。目前,实际包含的类型由属性决定,容器没有类型:

Data
    DataType { get; set; }
    Items<double>
        double Value;
    Items<string> 
        // ... and so on. Nasty stuff.

当然,最理想的是

Data<T>
    Items<T>
        T value

数据实例是在代码中从零开始创建的,并且可以从数据库加载。当然,工厂将在未来出现,但是Create方法的返回类型是什么呢?

更糟的是,我需要这个:

DataCollection
    // HERE'S THE PAIN: What's the type here?
    List of Data<> instances with differing types
foreach (? data in someDataCollection)
    if (thetypeof data is double)
        doSomething();
    else
        doSomethingElse();

现在,我可以解决这个问题,但我找不到一个干净的方法来解决这个问题。

我的第一个问题是DataCollection的声明。清单的类型是什么?List,所以它可以保存Data和Data ?

Typed<祝辞/无类型的设计

实际上有一个简单的方法来解决这个问题;您可以使用具有数据类型键和泛型Func<>类型值的Dictionary。然后将该类型传递给create方法,该方法随后根据该类型查找要在Dictionary中使用的Func<>,并调用该Func<>来创建或处理对象。

因为我是从伪代码工作,基本上它看起来像下面的东西;您可以使用它并修改它以满足您的需求,但这是基本思想。

首先,为所有数据对象创建父类;请注意,该类有一个查找字典,用于调用各种类型的函数,并且注意它是抽象的:

public abstract class Data
{
    // A Lookup dictionary for processing methods
    // Note this the functions just return something of type object; specialize as needed
    private static readonly IDictionary<Type, Func<object, Data>> _processFunctions = new Dictionary
        <Type, Func<object, Data>>()
         {
             {typeof(int), d => { return doSomethingForInt( (Data<int>) d); }},
             {typeof(string), d => { return doSomethingForString( (Data<string>) d); }},
             {typeof(double), d => { return doSomethingForDouble( (Data<double>) d); }},
         };
    // A field indicating the subtype; this will be used for lo
    private readonly Type TypeOfThis;
    protected Data(Type genericType)
    {
        TypeOfThis = genericType;
    }
    public Data Process()
    {
        return _processFunctions[this.TypeOfThis](this);
    }
}

现在子类Data具有可实例化的泛型类型:

class Data<T> : Data
{
    // Set the type on the parent class
    public Data() : base(typeof(T))
    {
    }
    // You can convert this to a collection, etc. as needed
    public T Items { get; set; }
    public static Data<T> CreateData<T>()
    {
        return new Data<T>();
    }
}
然后,您可以使用父类型创建一个DataCollection类。注意ProcessData()方法;它现在所做的就是遍历元素并对每个元素调用Process():
class DataCollection
{
    public  IList<Data> List = new List<Data>();
    public void ProcessData()
    {
        foreach (var d in List)
        {
            d.Process();
        }
    }
}

…你都准备好了!现在可以用不同类型的数据调用DataCollection:

DataCollection dc = new DataCollection();
dc.List.Add(new Data<int>());
dc.List.Add(new Data<string>());
dc.List.Add(new Data<double>());

dc.ProcessData();

我认为每次你需要在运行时数据类型上做if-条件,这意味着数据结构有问题。但是每次遇到这样的情况,我都很难解决。

我在这里要做的是把你的基本类型包装成某种适配器的转换方法(甚至可能是隐式的),并使它们都实现一个公共接口,比如IDoSomething。然后,可以分别定义doSomethingIntWrapperDoubleWrapper等中的行为。然后你的DataCollection应该是List<IDoSomething>类型,循环可以从接口调用data.DoSomething()方法。

通过隐式转换,您可以像data.Add(3)一样以自然的方式使用集合-您仍然可以添加项而无需包装原语