无法将基类(数据协定)转换为派生类

Posted

技术标签:

【中文标题】无法将基类(数据协定)转换为派生类【英文标题】:Unable to cast Base class (data contract) to derived class 【发布时间】:2013-04-29 20:30:38 【问题描述】:
[DataContract]
public class SearchCriteria

    [DataMember]
    public string CountryID  get; set;     


[DataContract]
public class CitySearchCriteria: SearchCriteria

    [DataMember]
    public string CityID  get; set; 

我正在 MVC 控制器操作中创建 SearchCriteria 的实例,并尝试 将其转换为 CitySearchCriteria。

SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.CountryID = "1";
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;

上述语句后的“citySearchCriteria”对象显示为 NULL 值。我期待它显示两个属性,CountryID 和 CityID,CountryID 填充,CityID 为空白......但它将对象设置为 NULL。

这里有什么解决方案? DataContract 对此有什么作用吗?

cmets 建议,您不能将基数转换为派生: 但实际上,在我看来,我已经成功地做到了,它只是在控制器操作中不起作用:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

这已成功转换,那么为什么在控制器操作中不能使用类似的东西呢?

【问题讨论】:

您不能从 Base 转换为 Derived。反之亦然 请看问题的最后两段 再次检查马丁的答案(第一个例子)。 【参考方案1】:

你不能这样投射!

如果您执行new,您将创建一个特定大小的新内存对象。在您的情况下,new SearchCriteria() 创建了一个新的内存对象,其大小足以容纳一个字符串,仅此而已。

在最后一行中,您执行searchCriteria as CitySearchCriteria 尝试将searchCriteria 中的对象转换为更大的类型CitySearchCriteria。但这是不可能的。您正在尝试将包含 1 个字符串的内存对象“转换”为可以包含 2 个字符串的内存对象。但是强制转换不会转换新的内存对象。新字符串的值是多少?它只是在水下检查您的引用searchCriteria 是否已经包含CitySearchCriteria 类型的对象。在您的情况下:它没有(对象的类型为SearchCriteria)并返回null

所以...下一个示例有效(因为 CitySearchCriteria 已经创建)。这也是您的解决方案:

SearchCriteria searchCriteria = new CitySearchCriteria(); 
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;

不起作用(因为尚未创建 CitySearchCriteria)。这是你的情况:

SearchCriteria searchCriteria = new SearchCriteria();
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;

这与下一个示例相同。 这确实有效(因为 SearchCriteria 已经创建):

object o = new SearchCriteria();
SearchCriteria searchCriteria = o as SearchCriteria;

不是(因为尚未创建 SearchCriteria)::

object o = new object();
SearchCriteria searchCriteria = o as SearchCriteria;

为了记录:我总是使用直接转换,而不是使用 as 的转换,除非您想明确测试对象是否属于该类型。

【讨论】:

它只是无法转换,因为根据他的实现,转换无法从基类转换为派生类。反之亦然。 我想这正是我所说的......不是吗?还是我错过了你的意思?我的文字中哪个例子不正确? 是的,第三个会起作用。对象可以包含任何类型。只要它拥有该类型,您就可以将其转换为任何类型。另一个例子是:object o = "Hello"; string s = o as string; 为什么你认为它不起作用? 我不是这个意思。 他的问题的解决方案在哪里? 解决方案是示例#1。【参考方案2】:

每个人都已经(并且正确地)告诉过您,您根本无法从 Base 转换为 Derived,但在我看来,您仍然不明白为什么该行在您的另一块代码中起作用的原因:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

我认为您对实例的“类型”有点困惑。你没有发布模型的定义,但我认为你有这样的东西:

public SearchCriteria SearchCriteria;

这并不意味着 SearchCriteria 总是包含 SearchCriteria 的实例,而只是它包含可以转换为 SearchCriteria 的类型的实例。在您的情况下,它可以包含 SearchCriteria 或 CitySearchCriteria 的实例。我想在你的代码中的某个地方你会发现类似的东西:

Model.SearchCriteria = new CitySearchCriteria();

这就是正确执行 yor cast 的原因。您可以看到该实例确实是一个 CitySearchCriteria(而不仅仅是 SearchCriteria 的一个实例),它在强制转换之前执行此代码:

MessageBox.Show(Model.SearchCriteria.GetType().FullName);

为了更好地理解,您可以尝试在工作转换之前修改 SearchCriteria 中的值,如下所示,结果发现转换不再起作用:

Model.SearchCriteria = new SearchCriteria();
MessageBox.Show(Model.SearchCriteria.GetType().FullName);
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;

【讨论】:

谢谢你,是的,你是对的,我对此有很多困惑。这些细节已经澄清了这一点,我可以看到我在编码时错在哪里。谢谢【参考方案3】:

您可以创建 CitySearchCriteria,并将其转换为 SearchCriteria。这样你只能看到 CountryId。稍后,您可以将其转换回 CitySearchCriteria,并查看 CountryId 和 CityId。

这与 DataContract 无关。在您的情况下,解决方案是创建 CitySearchCriteria 并将其转换为 SearchCriteria(如果需要)。

【讨论】:

我发现了两个类似的问题:***.com/questions/988658/…和***.com/questions/9885644/… 问题是,我的视图期待一个“SearchCriteria”对象,因为它是从多个地方调用的,根据调用控制器和操作,它可以有“CitySearchCriteria”、“StateSearchCriteria”等。另外,我已经在我的视图中成功地做到了这一点,比如 CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;并且工作正常,那么为什么不在控制器操作中呢?

以上是关于无法将基类(数据协定)转换为派生类的主要内容,如果未能解决你的问题,请参考以下文章

通过 C++ 中的 std 迭代器将基类转换为派生

我们可以将基类的私有成员继承到派生类的公共成员中吗?

与简单地创建派生类指针相比,将基类绑定到派生类有啥好处?

为啥以及何时使用多态性将基类指向 C++ 中的派生类 [重复]

将基类传递给函数而不是派生一个

将基类的对象传递给派生类的引用函数