双重调度和替代方案

red*_*man 11 .net c# double-dispatch

我试图找到一种更好的方法来处理一些不断增长的if构造来处理不同类型的类.这些类最终是包含不同值类型(int,DateTime等)的包装器,带有一些额外的状态信息.因此,这些类之间的主要区别在于它们包含的数据类型.虽然它们实现了通用接口,但它们也需要保存在同类集合中,因此它们还实现了非通用接口.类实例根据它们所代表的数据类型进行处理,并且它们的传播在此基础上继续或不继续.

虽然这不一定是.NET或C#问题,但我的代码是在C#中.

示例类:

interface ITimedValue {
 TimeSpan TimeStamp { get; }
}

interface ITimedValue<T> : ITimedValue {
 T Value { get; }
}

class NumericValue : ITimedValue<float> {
 public TimeSpan TimeStamp { get; private set; }
 public float Value { get; private set; }
}

class DateTimeValue : ITimedValue<DateTime> {
 public TimeSpan TimeStamp { get; private set; }
 public DateTime Value { get; private set; }
}

class NumericEvaluator {
 public void Evaluate(IEnumerable<ITimedValue> values) ...
}
Run Code Online (Sandbox Code Playgroud)

我提出了两个选择:

双重发货

我最近了解到访问者模式及其使用双重调度来处理这种情况.这很有吸引力,因为它会允许不需要的数据不传播(如果我们只想处理一个int,我们可以处理与DateTime不同的方式).此外,处理不同类型的行为将局限于处理调度的单个类.但是,如果/必须支持新的值类型,则需要进行相当多的维护.

联盟班

包含每个支持的值类型的属性的类可以是每个类存储的内容.对值的任何操作都会影响相应的组件.这比双调度策略更简单,维护更少,但这意味着每一段数据都会不必要地传播,因为你不能再按照"我不对该数据类型进行操作"的方式进行区分. ".但是,如果/当需要支持新类型时,它们只需要进入这个类(加上需要创建的任何其他类来支持新数据类型).

class UnionData {
 public int NumericValue;
 public DateTime DateTimeValue;
}
Run Code Online (Sandbox Code Playgroud)

有更好的选择吗?这两个选项中的任何一个都有什么我认为不应该的吗?

Pao*_*lla 3

方法 1,使用动态进行双重调度(信用转到http://blogs.msdn.com/b/curth/archive/2008/11/15/c-dynamic-and-multiple-dispatch.aspx)。基本上你可以像这样简化你的访客模式:

class Evaluator {
 public void Evaluate(IEnumerable<ITimedValue> values) {
    foreach(var v in values)
    {
        Eval((dynamic)(v));
    }
 }

 private void Eval(DateTimeValue d) {
    Console.WriteLine(d.Value.ToString() + " is a datetime");
 }

 private void Eval(NumericValue f) {
    Console.WriteLine(f.Value.ToString() + " is a float");
 }

}
Run Code Online (Sandbox Code Playgroud)

使用示例:

var l = new List<ITimedValue>(){
    new NumericValue(){Value= 5.1F}, 
    new DateTimeValue() {Value= DateTime.Now}};

new Evaluator()
    .Evaluate(l);
       // output:
       // 5,1 is a float
       // 29/02/2012 19:15:16 is a datetime
Run Code Online (Sandbox Code Playgroud)

方法 2 将使用 C# 中的 Union 类型,如 @Juliet此处提议的(此处的替代实现)