通用转换方法抛出InvalidCastException

时间:2014-03-31 11:09:15

标签: c# generics runtime .net

我想实现相同的简单通用转换方法,但在运行时我遇到错误。

所以场景非常简单。我有相同的服务,返回外部类型的项目列表。我有自己的WrapperExternal类,它只是包装这个类并向它公开一些额外的功能。我有一些继承自WrapExternal的类,并添加了不同的功能。

我想创建接受外部列表项列表并返回指定类型项目列表的通用方法。

我的申请代码:

    static void Main(string[] args)
    {
        var items = GetItemsFromServer();
        var converted = ConvertItems<SubWrapperExternal>(items).ToList();
    }

    public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
    {
        return externalItems
            .Where( item => true)
            .Select(item => (T)item);
    }

当您尝试运行此代码时,您将在第(t)行项中获得异常:

An unhandled exception of type 'System.InvalidCastException' occurred in ConsoleApplication1.exe 
Additional information: 
Unable to cast object of type 'ConsoleApplication1.WrapperExternal' to type 'ConsoleApplication1.SubWrapperExternal'.

你知道我怎样才能让它发挥作用?

测试应用程序代码:

namespace ConsoleApplication1
{
class Program
{
    static void Main(string[] args)
    {
        var items = GetItemsFromServer();

        var converted = ConvertItems<SubWrapperExternal>(items).ToList();

    }

    private static List<External> GetItemsFromServer()
    {
        return new List<External>
        {
            new External{Name = "A"},
            new External{Name = "B"},
            new External{Name = "C"},
        };
    }

    public static IEnumerable<T> ConvertItems<T>(IEnumerable<External> externalItems) where T : WrapperExternal
    {
        return externalItems
            .Where( item => true)
            .Select(item => (T)item);
    }
}

class External
{
    public string Name { get; set; }

}

class WrapperExternal
{
    public External External { get; private set; }

    public WrapperExternal(External external)
    {
        External = external;
    }

    public static explicit operator WrapperExternal(External item)
    {
        return item != null ? new WrapperExternal(item) : null;
    }

    public static implicit operator External(WrapperExternal item)
    {
        return item != null ? item.External : null;
    }
}

class SubWrapperExternal : WrapperExternal
{
    public SubWrapperExternal(External external)
        : base(external)
    {
    }

    public static explicit operator SubWrapperExternal(External item)
    {
        return item != null ? new SubWrapperExternal(item) : null;
    }

    public static implicit operator External(SubWrapperExternal item)
    {
        return item != null ? item.External : null;
    }
}
}

1 个答案:

答案 0 :(得分:2)

转换运算符非常适用于泛型 - 泛型不支持任何静态运算符重载。因此,(T)演员正在执行非转换类型检查(泛型需要为每个可能的T使用相同的IL,请记住) - 基本castclass

唯一的&#34;简单&#34;做你想做的事就是用dynamic作弊:

return externalItems.Select(item => (T)(dynamic)item);

由于C#特定的dynamic提供程序知道C#的所有通用规则,因此它知道转换运算符,并将按需应用它们。与此相关的性能成本略有下降,但它并不像第一眼看到的那样糟糕,因为每种类型的策略都被缓存(如IL) - 它不会执行每个项目的反射