【问题标题】:Casting to generic type in non-generic method在非泛型方法中转换为泛型类型
【发布时间】:2011-10-23 02:52:21
【问题描述】:

我现在在做什么:

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
我的GuidBO
持久BO

我想打印:

MyIntBO 1008
MyGuidBO 6135d49b-81bb-43d4-9b74-dd84c2d3cc29
持久BO

最优雅的方法是什么?

我想支持所有类型的键 - intlongGuid 等 - 所以我宁愿不进行多次转换。请注意,并非每个业务对象都实现该接口(有些没有一个主键)。

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

澄清:为了解决@Acaz Souza 和@Petar Ivanov 的答案,我们有几十个类分散在已经实现IPrimaryKeyed&lt;T&gt; 的多个程序集中。我不想通过扩展接口契约来破坏所有这些。如果我从头开始设计,他们的解决方案会奏效。

【问题讨论】:

    标签: c# generics c#-4.0 casting


    【解决方案1】:

    只需创建一个非泛型接口并将泛型接口替换为泛型抽象类即可。然后检查接口:

        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 是一个非常优雅的解决方案,如果我们从一开始就这样设计它是可行的。请参阅我上面的说明,了解为什么这对我的情况不是最佳的。我很抱歉没有将其包含在我的原始帖子中。
    • 顺便说一句,我不能使用抽象类,因为我已经有一个必需的基类,而 C# 是单继承的。我必须使用public interface IPrimaryKeyed&lt;out TKey&gt; : IPrimaryKeyed 并在每个业务对象上实现该属性。它们是生成的代码,所以它是可行的,但会很痛苦。
    【解决方案2】:

    使用反射似乎不是一个坏方法。

    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();
    }  
    

    【讨论】:

    • +1 - 如果我走那条路,可以节省一些时间。注意stuff 应该是_businessObject。我也可以缓存GetType() 的结果。
    • 这就是我最终使用的。我为 CanRead 添加了一项检查,并检查了 GetValue 的结果不为空。
    【解决方案3】:

    问题出在那一行:

    var keyed = _businessObject as IPrimaryKeyed<int>;
    

    你的其他类型不是IPrimaryKeyed&lt;int&gt;IPrimaryKeyed&lt;Guid&gt;,那么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"); } }
    }
    

    【讨论】:

    • 是的,我知道问题出在哪里。请参阅我对答案的澄清。另请注意,现有接口在其他地方使用;我不想简单地删除泛型。如果不是我的限制,@Petar Ivanov 的类似解决方案将是可行的。 +1,不过。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-30
    • 1970-01-01
    • 2021-02-16
    • 1970-01-01
    相关资源
    最近更新 更多