是否有可能让c#使用最特定类型的方法重载而不是基类型?
如果您有一个使用派生类型重载的方法,则在运行时调用的方法取决于变量的类型,即使基础对象实际上是派生类型:是否有可能让c#使用最特定类型的方法重载而不是基类型?,c#,inheritance,overloading,C#,Inheritance,Overloading,如果您有一个使用派生类型重载的方法,则在运行时调用的方法取决于变量的类型,即使基础对象实际上是派生类型: class Program { static void Main(string[] args) { BaseClass theBaseObject = new BaseClass { Foo = "FOO" }; DerivedClass theDerivedObject = new De
class Program
{
static void Main(string[] args)
{
BaseClass theBaseObject = new BaseClass
{
Foo = "FOO"
};
DerivedClass theDerivedObject = new DerivedClass
{
Foo = "FOO",
Bar = "BAR"
};
Processor processor = new Processor();
Console.WriteLine(processor.Compose(theBaseObject));
Console.WriteLine(processor.Compose(theDerivedObject));
Console.WriteLine(processor.Compose((BaseClass) theDerivedObject));
}
}
public class Processor
{
public string Compose(BaseClass item)
{
return item.Foo;
}
public string Compose(DerivedClass item)
{
return Compose((BaseClass)item) + item.Bar;
}
}
public class BaseClass
{
public string Foo { get; set; }
}
public class DerivedClass : BaseClass
{
public string Bar { get; set; }
}
实际产量:
FOO
FOOBAR
FOO
我想找到一种方法来改变这种行为,以便为给定参数调用最具体的方法
期望输出:
FOO
FOOBAR
FOOBAR // because theDerivedObject is an instance of DerivedClass
FOO
FOOBAR
这将允许对一组项目进行特定的处理,所有这些项目都来自于一个基础
这在c#中可能吗
编辑: 澄清-在实践中没有明确的强制转换,因为项目可能位于混合类型集合的列表中: 使用不带显式强制转换的列表的示例:
foreach (BaseClass item in new []{ theBaseObject, theDerivedObject })
{
Console.WriteLine(processor.Compose(item));
}
实际产量:
FOO
FOO
期望输出:
FOO
FOOBAR
FOOBAR // because theDerivedObject is an instance of DerivedClass
FOO
FOOBAR
显然,强制转换仍在发生,但要删除它并不容易。首先,您得到结果的原因您得到的结果是因为您特别声明了
将derived对象声明为DerivedClass
,因此它将以DerivedClass
作为参数并使用(基类)derivedObject)
您只是简单地告诉编译器(如果我对编译器有错误,请纠正我)或程序使用参数BaseClass
您要做的是以下选项之一
第一:
public class Processor
{
public string Compose(BaseClass item)
{
if (item is DerivedClass)
return Compose((DerivedClass) item);
return item.Foo;
}
public string Compose(DerivedClass item)
{
return item.Foo + item.Bar;
}
}
二号
public class Processor
{
public string Compose(BaseClass item)
{
if (item is DerivedClass)
{
var derived = (DerivedClass) item;
return derived.Foo + derived.Bar;
}
return item.Foo;
}
}
或者,您可能希望跳过ToString()
如果您不使用C#6.0,那么处理器将如下所示
public class Processor
{
public string Compose(BaseClass item)
{
var @class = item as DerivedClass;
if (@class != null)
{
return @class.ToString();
}
return item.ToString();
}
}
难怪你得到了你得到的。您重载了
Compose
方法。您声明了两个签名,一个用于基类,另一个用于派生类。然后多次调用该方法:
调用processor.Compose(基本对象)
Compose(基本类项)
调用processor.Compose(派生对象)
。在这里,有几种方法可能适合调用。编译器选择层次结构中基类最接近的方法,该方法本身就是Compose(派生类项)
DerivedClass
调用processor.Compose((基类)derived对象))
,因为您已告诉他这样做。它没有可供选择的选项Compose(基类项)
public class BaseClass
{
public string Foo { get; set; }
public virtual string GetComposeResult() { return Foo; }
}
public class DerivedClass : BaseClass
{
public string Bar { get; set; }
public override string GetComposeResult() { return Foo + Bar; }
}
在这种情况下,使用以下代码可以实现您所期望的
public class Processor
{
public string Compose(BaseClass item) { return item.GetComposeResult(); }
}
这段代码让我想起了这首诗: 但我正在考虑一个计划
把胡须染成绿色,
总是使用这么大的风扇
看不见他们。
首先,您的代码创建一个子类,但随后它将对象强制转换回基类,因此编译器无法看到实际的类型!示例中的重载在编译时解决,因此将调用
Compose(基类项)
通过隐藏所有重载,并公开一个接受基类并执行动态强制转换的方法,您可以扭转局面,让.NET为您动态解决重载问题:
public class Processor {
public string Compose(BaseClass item) {
return ComposeImpl((dynamic)item);
}
private string ComposeImpl(BaseClass item) {
return item.Foo;
}
private string ComposeImpl(DerivedClass item) {
return ComposeImpl((BaseClass)item) + item.Bar;
}
}
“魔力”就在这一行:
return ComposeImpl((dynamic)item);
项
被强制转换为动态
,它告诉系统必须根据基类
对象的运行时类型选择ComposeImpl
的实际重载。将其强制转换为基类时,本质上是告诉它忽略其自身的任何属性摆脱(基类)castI认为您可能对双重分派感兴趣,它利用了虚拟成员函数是在运行时选择的这一事实(与通过参数选择函数重载相反,后者是在编译时解决的,正如您所演示的)。其思想是,您的Processor.Compose()
方法只是“回调”参数的虚拟函数(然后在运行时解析为最派生的实现)。这个乒乓球是名称中出现“double”的原因。@JNF好吧,您告诉编译器选择哪个Compose()
。你不能告诉被施法的物体失去任何财产;它没有被修改。@PeterA.Schneider,它可以在其他上下文中使用,但在这里它被视为基本类型。编译器不会以任何方式引用它。奇怪的是,它对我起作用了,我得到了他想要的结果。我明白了,你不能使用Compose(基类项)的调用。是的,否则它会导致StackOverFlow异常,这是双重分派。我认为这是一种方法。你的代码看起来很酷,但实际上它导致了StackOverFlow例外哇,很好。所以dynamic
基本上可以将重载解析移到运行时?在我看来,对于像C++这样编译的语言来说,很难实现更少的运行时支持。但是很好,我通过动态学到了一些东西,这是一个很好的解决方案,因为它不需要更改参数类(可以在处理器中完成),并且当您有很多派生类型时,您不会得到一长串“If This then cast that”类型逻辑