【问题标题】:Why won't upcast to concrete type of another common interface为什么不向上转换为另一个通用接口的具体类型
【发布时间】:2015-10-15 19:23:04
【问题描述】:

为什么不能向上转换到另一个通用接口的不同具体类型。我在 linqpad 中创建了这个示例。现在我可以理解如果你在两个类之间有不同的属性,向上转换会失败,因为它无法完成对象。但是在这种情况下,我看不出为什么向上转型会失败。

void Main()
{
    ICommon test = new ConcreteA();

    ((ConcreteA)test).a.Dump();

    // this errors with: Unable to cast object of type 'ConcreteA' to type 'ConcreteB'.
    ((ConcreteB)test).a.Dump();
}

public interface ICommon
{
   string a {get; }
}

public class ConcreteA : ICommon
{
    public string a {
        get{ return "Concrete A"; }
    }
}

public class ConcreteB : ICommon
{
    public string a {
        get{ return "Concrete B"; }
    }
}

编译器是否应该能够将其视为从 double 转换为 int,如果 double 对于 int 而言太大,则会引发异常,但如果可以进行转换,编译器会执行此操作.为什么编译器不尝试将 ConcreteA 作为 ConcreteB 加载,如果 ConcreteB 中有额外的属性无法弄清楚,那么它会抛出。

【问题讨论】:

  • 你为什么要在那个场景中投射?只需使用a.Dump
  • 这不是 C# 功能。如果您希望能够在两个不同的自定义类之间进行转换,则需要定义自己的转换运算符。
  • 假设 ConcreteB 有另一个属性“x”(未在 ICommon 中定义)并且编译器允许该转换。当你打电话给((ConcreteB)test).x 会发生什么
  • “难道我的问题不完美吗?不,不,是喷子!”
  • 不是我投反对票。但说真的,两次反对票没什么大不了的。你现在有 2 票赞成!

标签: c# interface casting upcasting


【解决方案1】:

由于ConcreteAConcreteB 一无所知(在您的情况下,因为它们可能对属性a 有不同的实现),我建议您像这样为ConcreteB 实现显式运算符:

public class ConcreteA
{
    /* rest of your code ... */

    public static explicit operator ConcreteB(ConcreteA instance)
    {
        // implement converting from ConcreteA to ConcreteB
    }
}

有关显式运算符的更多信息:https://msdn.microsoft.com/en-us/library/xhbhezf4.aspx

【讨论】:

  • 是否有一个属性,它会自动尝试对具有相同名称的属性进行强制转换
  • @johnny5 如果你想在两个类之间映射属性,Automapper 是你的朋友 :)
  • 我有自动映射器,我不想这样做,我只是希望它内置到 C# 中。我一直在寻找最懒惰的解决方案
  • @johnny5 最懒惰的解决方案是为所有类型使用dynamic。当然,您将放弃 C# 类型系统提供的所有性能、安全性和可维护性。到那时,您还不如在 Python 中工作。
  • 请注意,这不会解决 OP 中遇到的错误,因为强制转换的源是接口类型的本地。用户定义的转换不会在运行时查找(除非表达式是动态的),它们必须在编译时解决。
【解决方案2】:

因为您试图转换为与第一个其他类无关的不同类,它支持相同的接口。您正在尝试做的是某种 C# 不支持的 Duck 类型。

在您的情况下,您想直接在接口上调用该方法,而无需像这样:

test.a.Dump()

这就是您首先要使用该界面的原因。它是一个类“它支持什么能力”的契约。

【讨论】:

  • 我不明白那个逻辑。。接口的重点是你不必关心具体的类型是什么!
  • @Blorgbeard 是的,我只是想这样做,因为我使用稍后要序列化的接口,但我不想实现 ISerializeable
  • 嗯,.net 附带的序列化器已经可以很好地序列化所有简单的东西和一些复杂的东西。我会在 MSDN 或 stacko 上查看序列化,看看在这个方向上是否有帮助使其变得容易。 IIRC 有一些属性,您可以在其中指示序列化程序执行某些行为,
猜你喜欢
  • 2012-11-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
相关资源
最近更新 更多