2011-10-23 175 views
0

我现在做:铸造泛型类型的非泛型方法

void Main() 
{ 
    var command1 = new PersistenceCommand(new MyIntBO()); 
    var command2 = new PersistenceCommand(new MyGuidBO()); 
    var command3 = new PersistenceCommand(new PersistentBO()); 

    Console.WriteLine(command1.ToString()); 
    Console.WriteLine(command2.ToString()); 
    Console.WriteLine(command3.ToString()); 
} 

public class PersistenceCommand 
{ 
    public PersistenceCommand(PersistentBO businessObject) 
    { 
     _businessObject = businessObject; 
    } 

    public override string ToString() 
    { 
     string result = _businessObject.GetType().Name; 

     var keyed = _businessObject as IPrimaryKeyed<int>; 

     if (keyed != null) 
     { 
      result += " " + keyed.Id.ToString(); 
     } 

     return result; 
    } 

    private readonly PersistentBO _businessObject; 
} 

public interface IPrimaryKeyed<out TKey> 
{ 
    TKey Id { get; } 
} 

public class PersistentBO {} 

public class MyIntBO : PersistentBO, IPrimaryKeyed<int> 
{ 
    public int Id { get { return 1008; } } 
} 

public class MyGuidBO : PersistentBO, IPrimaryKeyed<Guid> 
{ 
    public Guid Id 
    { 
     get 
     { 
      return new Guid("6135d49b-81bb-43d4-9b74-dd84c2d3cc29"); 
     } 
    } 
} 

此打印:

MyIntBO 1008 
MyGuidBO 
PersistentBO

我想它想打印:

MyIntBO 1008 
MyGuidBO 6135d49b-81bb-43d4-9b74-dd84c2d3cc29 
PersistentBO

什么是最优雅的方式来做到这一点?

我想支持所有类型的键 - int,long,Guid等 - 所以我宁愿不做多个演员。请注意,并非每个业务对象都实现该接口(有些没有单个主键)。

我意识到我可以使用反射并尝试访问Id属性。我想知道是否有更好的解决方案。

澄清:为了解决@Acaz索萨和@Petar伊万诺夫的答案,我们有几十个散落在已经实现IPrimaryKeyed<T>多个组件类。我不想通过扩展接口合约来打破所有这些问题。如果我从头开始设计,他们的解决方案就可以工作。

回答

1

使用反射似乎不是一个坏的方法去这里。

ToString方法:

// for getting the Id prop 
var identProp = _businessObject.GetType().GetProperty("Id"); 
string result = _businessObject.GetType().Name; 

if (identProp != null) 
{ 
    result += " " + identProp.GetValue(_businessObject, null).ToString(); 
} 
+0

+1 - 如果我走这条路线,可以节省一些时间。请注意'stuff'应该是'_businessObject'。我也可以缓存'GetType()'的结果。 – TrueWill

+0

对错字很好,固定 –

+0

这就是我最终使用的。我为CanRead添加了一个检查,并且GetValue的结果不为null。 – TrueWill

1

的问题是在该行:

var keyed = _businessObject as IPrimaryKeyed<int>; 

你的另一种类型是不IPrimaryKeyed<int>IPrimaryKeyed<Guid>,那么if (keyed != null)是假的。

你可以试着这样做:

static void Main() 
{ 
    var command1 = new PersistenceCommand(new MyIntBO()); 
    var command2 = new PersistenceCommand(new MyGuidBO()); 
    var command3 = new PersistenceCommand(new PersistentBO()); 

    Console.WriteLine(command1.ToString()); 
    Console.WriteLine(command2.ToString()); 
    Console.WriteLine(command3.ToString()); 
    Console.ReadLine(); 
} 

public class PersistenceCommand 
{ 
    public PersistenceCommand(PersistentBO businessObject) 
    { 
     _businessObject = businessObject; 
    } 

    public override string ToString() 
    { 
     string result = _businessObject.GetType().Name; 

     var keyed = _businessObject as IPrimaryKeyed; 

     if (keyed != null) 
     { 
      result += " " + keyed.Id.ToString(); 
     } 

     return result; 
    } 

    private readonly PersistentBO _businessObject; 
} 

public interface IPrimaryKeyed 
{ 
    object Id { get; } 
} 

public class PersistentBO { } 

public class MyIntBO : PersistentBO, IPrimaryKeyed 
{ 
    public object Id { get { return 1008; } } 
} 

public class MyGuidBO : PersistentBO, IPrimaryKeyed 
{ 
    public object Id { get { return new Guid("6135d49b-81bb-43d4-9b74-dd84c2d3cc29"); } } 
} 
+0

是的,我知道问题所在。请看我对答案的澄清。还要注意现有的接口在其他地方使用;我不想简单地删除泛型。如果不是因为我的限制,@Petar Ivanov的类似解决方案可行。 +1,但。 – TrueWill

2

只要创建一个非通用接口和更换一般一个与通用抽象类。然后检查接口:

public interface IPrimaryKeyed 
    { 
     object ObjId { get; } 
    } 

    public abstract class PrimaryKeyed<TKey> : IPrimaryKeyed 
    { 
     public object ObjId { get { return Id; } } 
     public abstract TKey Id { get; } 
    } 

--- 

public override string ToString() 
{ 
    string result = _businessObject.GetType().Name; 

    var keyed = _businessObject as IPrimaryKeyed; 

    if (keyed != null) 
    { 
     result += " " + keyed.ObjId.ToString(); 
    } 

    return result; 
} 
+0

+1为一个非常优雅的解决方案,如果我们从一开始就设计它,这将是可行的。请看我上面的澄清为什么这不是我的情况最佳。我的道歉不包括我原来的帖子。 – TrueWill

+0

顺便说一句,我不能使用抽象类,因为我已经有了一个必需的基类,C#是单继承。我必须使用'public interface IPrimaryKeyed :IPrimaryKeyed'并在每个业务对象上实现该属性。他们生成的代码,所以它是可行的,但它会是一个痛苦。 – TrueWill