Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/284.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
是否有可能让c#使用最特定类型的方法重载而不是基类型?_C#_Inheritance_Overloading - Fatal编程技术网

是否有可能让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”类型逻辑