分配兼容性有问题?

时间:2014-05-19 01:26:31

标签: c# inheritance polymorphism

我要做的是使用单个调用返回基类的2个扩展的集合。这就是我所拥有的:

public interface IView
{
   int Id { get; set; }
}

然后我有一个实现此接口的域模型

public class View: IView
{
   public int Id { get; set; }
}

然后我有几个继承自基类的类

public class ViewA: View
{ 
   public string PropertyA { get; set; }
}

public class ViewB: View
{
   public string PropertyB { get; set; }
}

从这里我有一个列表,我试图包含两者:

var views = new List<IView>();

并从我的基础创建一个视图,因为ViewA和ViewB都有ID

var view = new View();
view.Id = 1;

现在我正在尝试将其转换为ViewA,所以我可以这样设置PropertyA:

var viewA = (ViewA)view;

但是调试器告诉我我无法将“视图”转换为ViewA(编译得很好)。

Unable to cast object of type 'View' to type 'ViewA'

我确信我对界面的理解缺少了一些东西 - &gt;基类继承但我认为你可以通过这种方式将“较小”类强制转换为“更多定义”类。阅读关于协方差,逆变和赋值兼容性,我认为我应该能够做到这一点;显然不是..

我想要做的是返回两种类型的视图的集合(因此列表),以便我可以在需要时将它们转换为更定义的视图,并在我只需要公共属性时将它们保留为基本视图

我宁愿在ViewA和ViewB中没有重复的属性,我正在尝试做什么,或者我只是把这一切都弄错了?

4 个答案:

答案 0 :(得分:3)

  

我确信我对界面的理解缺少了一些东西 - &gt;基类继承但我认为你可以通过这种方式将“较小”类强制转换为“更多定义”类。阅读关于协方差,逆变和赋值兼容性,我认为我应该能够做到这一点;显然不是..

你已经倒退了(我想)。您始终可以将派生类型的实例强制转换为基本类型,但不能反过来。如果将实例强制转换为派生类型,则它必须是运行时该类型的实例。

看起来你要做的就是以某种方式从ViewA的实例创建View的实例。这不是铸造工作的方式。

以下是 工作可能有用的示例。如果您有自己的观点列表:

var views = new List<IView>();

然后添加ViewA的实例:

views.Add(new ViewA());

现在,编译器“不知道”views[0]ViewA - 毕竟它是IView的列表。在这种情况下,您知道的不仅仅是编译器,而且演员阵容是合适的:

var viewA = (ViewA)views[0];

你还提到:

  

我宁愿在ViewA和ViewB中没有重复的属性

除非我遗漏了什么,否则你没有复制任何属性。 ViewAViewB具有不同的属性,并从Id类继承View属性。

换句话说,这很好看:

var view = new ViewA();

view.Id = 4;

答案 1 :(得分:1)

ViewAViewB的实例添加到列表中,而不仅仅是View

var views = new List<IView>();

var view = new ViewA();  // add an instance of viewA
views.Add(view);

您可以直接访问项目(无需转换,感谢Andrew)更改基类的“Id”属性,因为该属性也在界面中定义:

var view = (View)views[0];
view.Id = 999;

或测试类型以访问其他更具体的属性:

var viewB = views[0] as ViewB;  // first element is a ViewA, so viewB is null

if (viewB != null)
{
    viewB.PropertyB = "someValue";  // doesn't run because viewB is null
}

var viewA = views[0] as ViewA;

if (viewA != null)
{
    viewA.PropertyA = "someOtherValue";  // runs - you have an instance of viewA
}

答案 2 :(得分:0)

不,你不能将“较小”类强制转换为“更明确”的类。 但是您可以将viewA和viewB转换为View列表,以便在获取公共属性时使用。

答案 3 :(得分:0)

用于创建对象的类型是它应该始终的类型 - 它永远不会改变。

因此,您要将您的实例创建为:

var view = new View();

因为它继承了IView,您可以将其引用为View,但它永远不会改变View的类型。

因此,当您尝试将其强制转换为ViewA时,它会失败。它永远不会是ViewA,除非你这样创建它。

所以,如果你这样做:

var view = new ViewA();

然后可以将其引用为IViewViewViewA,但它始终为ViewA类型。