C# 基于类型处理不同的逻辑

C# 基于类型处理不同的逻辑,c#,C#,我有类Foo和一个实例方法Foo.M,返回类型T和签名M(条形)。对T(T:AbstractBaseClass)有一个约束,因此我确信T有一个属性T.SomeProperty(和一个无参数构造函数约束)。假设M必须根据bar以及T的具体类型设置T.SomeProperty的值。我不希望我的代码看起来像 T t = new T(); if(typeof(T) == T1) { T.SomeProperty = // some function of bar } else if(typeo

我有
类Foo
和一个实例方法
Foo.M
,返回类型
T
和签名
M(条形)
。对
T
T:AbstractBaseClass
)有一个约束,因此我确信
T
有一个属性
T.SomeProperty
(和一个无参数构造函数约束)。假设
M
必须根据
bar
以及
T
的具体类型设置
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;
    }
}

我唯一不喜欢的是它使用了一个泛型接口,而泛型类型参数从未出现在接口中。我想我曾经看到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();
        }
    }
}
class-Foo
其中T:AbstractBaseClass,new()
{
TM(巴)
{
T=新的T();
if(类型(T)=T1)
{
t、 SomeProperty=bar.SomeMethod();
}
else if(类型(T)=T2)
{
t、 SomeProperty=bar.SomeOtherMethod();
}
否则如果(类型(T)=T3)
{
t、 SomeProperty==bar.YetAnotherMethod();
}
}
}
您可以这样做:

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

    t.SomeProperty = barFunction();
}
TM(条形、函数条形)
{
T=新的T();
t、 SomeProperty=barFunction();
}

它不需要与Bar方法紧密耦合。在
Func
委托上。

好的,这是一个完整的程序。出于示例的考虑,我认为Bar是一个包含有趣值的类(这里是100)。我认为foo.M是一个例程,如果类型参数是ConcreteClass1,它想在条内的数字上加73;如果类型参数是ConcreteClass2,它将希望从条内的数字中减去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;
    }
使用系统;
使用系统诊断;
命名空间控制台应用程序33{
公共课程{
公共静态void Main(){
var foo1=新的Foo();
var foo2=新的Foo();
var棒=新棒(100);
var result1=foo1.M(巴);
var result2=foo2.M(bar);
Debug.Print(“result1.SomeProperty=“+result1.SomeProperty”);
Debug.Print(“result2.SomeProperty=“+result2.SomeProperty”);
}
}
//----------------------------------------------------------------------------
//这些定义可以出现在项目1中
//请注意,项目1对Bar没有任何依赖关系
//----------------------------------------------------------------------------
/// 
///此接口需要层次结构中的每个类对应一行
/// 
公共接口IABCVisitor{
T访视(抽象基类x);
T访问(1 x类);
T访问(2 x类);
}
公共抽象类AbstractBaseClass{
公共int SomeProperty{get;set;}
/// 
///所有AbstractBaseClass的子类都需要重写此属性
/// 
公共虚拟T接受访问者(IABCVisitor访问者){
回访者。参观(本);
}
}
公共类ConcreteClass1:AbstractBaseClass{
公共覆盖T接受访问者(IABCVisitor访问者){
回访者。参观(本);
}
}
公共类ConcreteClass2:AbstractBaseClass{
公共覆盖T接受访问者(IABCVisitor访问者){
回访者。参观(本);
}
}
//----------------------------------------------------------------------------
//这些定义可以出现在项目2中
//----------------------------------------------------------------------------
公共类酒吧{
public int MagicValue{get;private set;}
公共酒吧(int magicValue){
MagicValue=MagicValue;
}
}
公共类Foo,其中T:AbstractBaseClass,new(){
公共T M(酒吧){
T=新的T();
t、 SomeProperty=t.AcceptVisitor(新的CalculateRightValue(bar));
返回t;
}
}
公共类CalculateRightValue:IABCVisitor{
私人只读条;
公共CalculateRightValue(条形){
这个.bar=bar;
}
公共int访问(AbstractBaseClass x){
抛出新的NotImplementedException(“未为类型“+x.GetType().Name”实现);
}
公众参观(1 x类){
返回条MagicValue+73;
}
公共int访问(ConcreteClass2 x){
返回条MagicValue-12;
}

请解释,我不懂。您可以在AbstractBaseClass中有一个方法,类似于Apply(b栏)当然,这会为您设置一些可以重载的属性……或者接受像Func这样的投影。@詹姆斯·迈克尔·黑尔:这使得
AbstractBaseClass
依赖于
Bar
,这是我不想要的。我明白了,然后我会在我的评论中使用投影模型,这与保罗下面的回答类似。您将无法使用它从泛型类型转换而来,因此您不能依赖未在基类中定义的具体方法。那么,为什么有一个带有参数的接口没有任何用途?如果您只是从ISomePropertyStrategy中删除类型参数,您的程序会发生什么变化?不完全如此。
Bar
上没有生成这些值取决于o
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;
    }