无法将Base类(数据协定)强制转换为派生类

Nir*_*man 8 c# oop casting derived-class datacontract

[DataContract]
public class SearchCriteria
{
    [DataMember]
    public string CountryID { get; set; }    
}

[DataContract]
public class CitySearchCriteria: SearchCriteria
{
    [DataMember]
    public string CityID { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

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

SearchCriteria searchCriteria = new SearchCriteria();
searchCriteria.CountryID = "1";
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
Run Code Online (Sandbox Code Playgroud)

上述语句后面的"citySearchCriteria"对象显示NULL值.我希望它显示属性,CountryID和CityID,其中CountryID已填充,CityID为空......但它将对象设置为NULL.

这可能是什么解决方案?DataContract有什么用呢?

评论建议,你不能将基数转换为派生:但实际上,我已经在我的视图中成功完成了这一点,它只是在控制器操作中不起作用:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
Run Code Online (Sandbox Code Playgroud)

这是成功转换的,为什么类似的东西不能在控制器动作中工作呢?

Mar*_*der 9

你不能这样投!

如果您这样做new,则创建一个特定大小的新内存对象.在你的情况下new SearchCriteria()创建一个新的内存对象,其大小足以容纳一个字符串,仅此而已.

在最后一行中,您searchCriteria as CitySearchCriteria尝试将对象searchCriteria转换为更大的类型CitySearchCriteria.但它无法完成.您正在尝试将包含1个字符串的内存对象"转换"为可容纳2个字符串的内存对象.但是转换不会转换新的内存对象.新字符串的价值是多少?它只是在水下查看你的引用是否searchCriteria已包含类型的对象CitySearchCriteria.在你的情况下:它不(对象是类型SearchCriteria)并返回null.

所以...下一个示例是可行的(因为已经创建了CitySearchCriteria).这也是你的解决方案:

SearchCriteria searchCriteria = new CitySearchCriteria(); 
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
Run Code Online (Sandbox Code Playgroud)

而这并不能正常工作(因为CitySearchCriteria尚未创建).这是你的情况:

SearchCriteria searchCriteria = new SearchCriteria();
CitySearchCriteria citySearchCriteria = searchCriteria as CitySearchCriteria;
Run Code Online (Sandbox Code Playgroud)

这跟下一个例子是一回事.
确实有效(因为已经创建了SearchCriteria):

object o = new SearchCriteria();
SearchCriteria searchCriteria = o as SearchCriteria;
Run Code Online (Sandbox Code Playgroud)

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

object o = new object();
SearchCriteria searchCriteria = o as SearchCriteria;
Run Code Online (Sandbox Code Playgroud)

对于记录:我总是使用直接强制转换,而不是使用强制转换as,除非您想要显式测试对象是否属于该类型.


Fra*_*lli 7

每个人都已经(并且正确地)告诉过你,你根本无法从Base转换为Derived,但在我看来,你仍然没有理解为什么这条线在你的代码的另一块中起作用:

CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
Run Code Online (Sandbox Code Playgroud)

我认为你对实例的"类型"有点困惑.你没有发布Model的定义,但我认为你有这样的东西:

public SearchCriteria SearchCriteria;
Run Code Online (Sandbox Code Playgroud)

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

Model.SearchCriteria = new CitySearchCriteria();
Run Code Online (Sandbox Code Playgroud)

这是允许正确执行yor强制转换的原因.你可以看到实例确实是一个CitySearchCriteria(而不仅仅是SearchCriteria的一个实例)在演员之前执行这段代码:

MessageBox.Show(Model.SearchCriteria.GetType().FullName;
Run Code Online (Sandbox Code Playgroud)

为了更好地理解你可以尝试在工作演员之前修改SearchCriteria中的值,如下所示,只是为了发现演员阵容不再有效:

Model.SearchCriteria = new SearchCriteria();
MessageBox.Show(Model.SearchCriteria.GetType().FullName;
CitySearchCriteria citySearchCriteria = (CitySearchCriteria)Model.SearchCriteria;
Run Code Online (Sandbox Code Playgroud)