我有class Foo<T>
和实例方法Foo<T>.M
,返回类型为T
,签名为M(Bar bar)
。 T
(T : AbstractBaseClass
)存在约束,因此我确定T
具有属性T.SomeProperty
(以及无参数构造函数约束)。假设M
必须根据T.SomeProperty
设置bar
的值以及T
的具体类型。我不希望我的代码看起来像
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
依赖于一些我不希望它依赖的东西。
这里我最好的选择是什么?
这就是我的意思:
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's idea:
上徘徊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的评论,他说这不是一个好主意,但我不记得了。遗憾。
答案 0 :(得分:2)
所以你有这个:
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>
代表Here is some information。{/ p>
答案 1 :(得分:1)
好的,这是一个完整的程序。为了这个例子,我把Bar作为一个拥有有趣值的类(这里是100)。如果类型参数是ConcreteClass1,我把foo.M作为一个例程,想要在Bar中的数字加73。如果类型参数是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;
}
答案 2 :(得分:0)
这看起来像是Visitor Pattern
的非常经典的应用程序