在非泛型方法中转换为泛型类型

时间:2011-10-23 02:52:22

标签: c# generics c#-4.0 casting

我现在在做什么:

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

最优雅的方法是什么?

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

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

澄清:为了解决@Acaz Souza和@Petar Ivanov的答案,我们在已经实施IPrimaryKeyed<T>的多个程序集上分散了数十个类。我不想通过扩展接口契约来打破所有这些。如果我从头开始设计,他们的解决方案就可以了。

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分: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"); } }
}

答案 2 :(得分: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();
}