【问题标题】:How to upcast using Generic Type Class to Formal Implementation?如何使用泛型类型类向上转换为正式实现?
【发布时间】:2018-08-27 09:35:57
【问题描述】:

当我们尝试从 Generic Type 类向上转换为正式实现时,会出现转换错误。

在下面的代码中,您可以看到我有一个 FormalClass,它是一个 GenericTypeClass 的实现。当我尝试从 GenericTypeClass 向上转换为 FormalClass 时,它会出现此错误:

[System.InvalidCastException:无法将“GenericTypeClass`1[TestType]”类型的对象转换为“FormalClass”类型。]

我知道这行不通,但是如果您需要进行向上转换,解决它的最佳方法是什么?自动映射器? json序列化?其他?

下面是一个 dotnetfiddle (https://dotnetfiddle.net/LLg0vp) 示例:

using System;

public class Program
{
    public static void Main()
    {
        var a = new GenericTypeClass<TestType>();

        var b = a as FormalClass;
        if (b == null)
            Console.WriteLine("'a as Formal' Is NULL");

        try
        {
            var c = (FormalClass)a;
        }
        catch (Exception ex)
        {
            Console.WriteLine("'(FormalClass)a' gives this error: " + ex.Message);
        }
    }
}

public class FormalClass : GenericTypeClass<TestType>
{
}

public class GenericTypeClass<T>
    where T : class, IType
{
}

public class TestType : IType
{
}

public interface IType
{
}

【问题讨论】:

  • 为什么该演员阵容有效? GenericTypeClass&lt;TestType&gt; != FormalClass
  • 我知道这行不通,当您想做类似的事情时,我正在寻找最佳解决方案。就像使用自动映射器...
  • 如果只需要向上转换,只需将var a = 替换为object a = 或创建一个基类GenericTypeClass&lt;T&gt; 继承自BaseClass a = 应该这样做

标签: c# .net generics casting upcasting


【解决方案1】:

您无法通过继承来实现这一点。一旦创建了具有 GenericTypeClass&lt;TestType&gt; 类型的对象,它就永远不会变成 FormalClass

选项:

  1. 研究如何创建 FormalClass 而不是 GenericTypeClass&lt;TestType&gt;
    • 这可能很简单也可能很复杂,具体取决于您的代码流。
  2. 创建一个新的FormalClass 并使用 Automapper 将属性值复制到其中
    • 对新 FormalClass 对象中属性的更改不会影响原始 Generic 对象。
  3. 不是让FormalClass 继承自GenericTypeClass&lt;TestType&gt;', make it a wrapper for aGenericTypeClass' 并在构造函数中传入`GenericTypeClass'。
    • 添加到 Generic 类的任何新属性都必须添加到 FormalClass

我已经包含了包装方法的代码示例。


using System;

public class Program
{
    public static void Main()
    {
        var a = new GenericTypeClass<TestType>();
        var b = new FormalClass(a);
        a.Name = "NameA";
        b.Name = "NameB";
        Console.WriteLine(a.Name);
        Console.WriteLine(b.Name);
    }
}

public class FormalClass
{
    GenericTypeClass<TestType> _inner;
    public FormalClass(GenericTypeClass<TestType> parameter)
    {
        _inner = parameter;
    }

    public string Name
    {
        get
        {
            return _inner.Name;
        }

        set
        {
            _inner.Name = value;
        }
    }
}

public class GenericTypeClass<T>
    where T : class, IType
{
    public string Name
    {
        get;
        set;
    }
}

public class TestType : IType
{
}

public interface IType
{
}

【讨论】:

  • 这是一个很好的包装解决方案。就我而言,我遇到了这个问题,因为我正在重构一个类,我需要使用类型参数使其成为泛型,并且由于它在任何地方都使用并且我不想将类型传递给它,我只是派生它使用相同名称的 Generic 以保持重构简单。
  • 关键在于查看您创建实例的位置。如果您首先将其创建为“FormalClass”,则可以将其用作“GenericTypeClass”。如果您有一个最初创建为 FormalClass 的“GenericTypeClass”,那么您可以使用 as 运算符(或强制转换)来引用它。但是如果不能将它创建为 FormalClass,那么包装器是一个不错的选择。
【解决方案2】:

你的例子可以简化如下(注意泛型在这里没有任何作用):

void Main()
{
    var a = new BaseClass();

    var b = a as DerivedClass;
    if (b == null)
        Console.WriteLine("'a as Derived' Is NULL");
}


public class BaseClass
{
}

public class DerivedClass : BaseClass
{
}

...果然,这永远行不通。派生类可以转换回基类,但不能反过来。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多