根据类型处理不同的逻辑

本文关键字:类型 处理 | 更新日期: 2023-09-27 18:07:58

我有class Foo<T>和一个返回类型T和签名M(Bar bar)的实例方法Foo<T>.M。对T (T : AbstractBaseClass)有一个约束,因此我确定T具有属性T.SomeProperty(和无参数构造函数约束)。假设M必须根据barT的具体类型设置T.SomeProperty的值。我不希望我的代码看起来像

T t = new T();
if(typeof(T) == T1) {
     T.SomeProperty = // some function of bar
}
else if(typeof(T) == T2) {
     T.SomeProperty = // some function of bar
}
else if(typeof(T) == T3) {
     T.SomeProperty == // some function of bar
}

我不想在T上放置一个实例方法,它从Bar中获取值来填充T.SomeProperty,因为这会使我的T s依赖于一些我不想让它们依赖的东西。

我最好的选择是什么?

我的意思是:

class AbstractBaseClass {
    public int SomeProperty { get; set; }
}
class Foo<T> where T : AbstractBaseClass, new() {
    public T M(Bar bar) {
        T t = new T();
        t.SomeProperty = // function of bar, typeof(T)
        return t;
    }
}

如何编写M,但避免类型参数T上的逐类型逻辑?

编辑:

这个怎么样?这是Corey的想法:

interface ISomePropertyStrategy<T> {
    int GetSomeProperty(Bar bar);
}
class SomePropertyStrategyForConcreteClass1 :
    ISomePropertyStrategy<ConcreteClass1> {
    public int GetSomeProperty(Bar bar) { return bar.MagicValue + 73; }
}
class SomePropertyStrategyForConcreteClass2 :
    ISomePropertyStrategy<ConcreteClass2> {
    public int GetSomeProperty(Bar bar) { return bar.MagicValue - 12; }
}
class Foo<T> where T : AbstractBaseClass, new() {
    private readonly ISomePropertyStrategy<T> strategy;
    public Foo<T>(ISomePropertyStrategy<T> strategy) {
        this.stragety = strategy;
    }
    public T M(Bar bar) {
        T t = new T();
        t.SomeProperty = this.strategy.GetSomeProperty(bar);
        return t;
    }
 }

我唯一不喜欢的是它使用了泛型接口,泛型类型参数永远不会出现在接口中。我记得我曾经看过Eric Lippert的评论,他说这不是一个好主意,但我不记得了。对不起。

根据类型处理不同的逻辑

所以你有这个:

class Foo<T>
    where T : AbstractBaseClass, new()
{
    T M( Bar bar )
    {
        T t = new T();
        if ( typeof (T) == T1 )
        {
            t.SomeProperty = bar.SomeMethod();
        }
        else if ( typeof (T) == T2 )
        {
            t.SomeProperty = bar.SomeOtherMethod();
        }
        else if ( typeof (T) == T3 )
        {
            t.SomeProperty == bar.YetAnotherMethod();
        }
    }
}

你可以这样做:

T M( Bar bar, Func<object> barFunction )
{
    T t = new T();
    t.SomeProperty = barFunction();
}

它不需要与你的Bar方法紧密耦合。以下是Func<T>委托的一些信息。

好的,这是一个完整的程序。出于示例的考虑,我将Bar作为某个类,它持有一个有趣的值(这里是100)。我吃了。M是一个例程,如果类型参数是ConcreteClass1,则要将73添加到Bar中的数字;如果类型参数为ConcreteClass2,则需要从Bar中的数字减去12。

接口IABCVisitor和虚拟方法AcceptVisitor(每个类一个)可能看起来开销很大,但好处是您只需要支付一次开销:一旦将此模式添加到类层次结构中,您就可以一次又一次地重用它,每当调用者想要基于类型执行自定义逻辑时。我希望下面的程序对你有意义。

using System;
using System.Diagnostics;
namespace ConsoleApplication33 {
  public class Program {
    public static void Main() {
      var foo1=new Foo<ConcreteClass1>();
      var foo2=new Foo<ConcreteClass2>();
      var bar=new Bar(100);
      var result1=foo1.M(bar);
      var result2=foo2.M(bar);
      Debug.Print("result1.SomeProperty="+result1.SomeProperty);
      Debug.Print("result2.SomeProperty="+result2.SomeProperty);
    }
  }
  //----------------------------------------------------------------------------
  // these definitions can appear in project 1
  // notice that project 1 does not have any dependencies on Bar
  //----------------------------------------------------------------------------
  /// <summary>
  /// This interface needs a line for each class in the hierarchy
  /// </summary>
  public interface IABCVisitor<out T> {
    T Visit(AbstractBaseClass x);
    T Visit(ConcreteClass1 x);
    T Visit(ConcreteClass2 x);
  }
  public abstract class AbstractBaseClass {
    public int SomeProperty { get; set; }
    /// <summary>
    /// All of AbstractBaseClasses' children need to override this property
    /// </summary>
    public virtual T AcceptVisitor<T>(IABCVisitor<T> visitor) {
      return visitor.Visit(this);
    }
  }
  public class ConcreteClass1 : AbstractBaseClass {
    public override T AcceptVisitor<T>(IABCVisitor<T> visitor) {
      return visitor.Visit(this);
    }
  }
  public class ConcreteClass2 : AbstractBaseClass {
    public override T AcceptVisitor<T>(IABCVisitor<T> visitor) {
      return visitor.Visit(this);
    }
  }
  //----------------------------------------------------------------------------
  // these definitions can appear in project 2
  //----------------------------------------------------------------------------
  public class Bar {
    public int MagicValue { get; private set; }
    public Bar(int magicValue) {
      MagicValue=magicValue;
    }
  }
  public class Foo<T> where T : AbstractBaseClass, new() {
    public T M(Bar bar) {
      T t=new T();
      t.SomeProperty=t.AcceptVisitor(new CalculateTheRightValue(bar));
      return t;
    }
  }
  public class CalculateTheRightValue : IABCVisitor<int> {
    private readonly Bar bar;
    public CalculateTheRightValue(Bar bar) {
      this.bar=bar;
    }
    public int Visit(AbstractBaseClass x) {
      throw new NotImplementedException("not implemented for type "+x.GetType().Name);
    }
    public int Visit(ConcreteClass1 x) {
      return bar.MagicValue+73;
    }
    public int Visit(ConcreteClass2 x) {
      return bar.MagicValue-12;
    }

这看起来像是一个非常经典的访问者模式的应用程序