26

我有一次面试,被问到以下问题:

问题:具有相同名称和签名但返回类型不同的方法。有没有可能,这种类型叫什么?他问我。

有人可以告诉我以下内容:

  1. 在任何情况下都可能出现上述情况(例如基类中的一个和派生类中的一个?)如果是这样,它是什么类型?像编译或运行时多态?

  2. 在编译时多态中,如果方法的返回类型与签名也不同怎么办?但只有函数的名称是相同的。它仍然是编译时多态性吗?

  3. 在覆盖中,如果我有不同的返回类型但方法名称和签名相同怎么办?是否可以 ?(他问我这个问题,我回答错了:()请帮助我。

谢谢

4

9 回答 9

41

  • 我认为问题是关于返回类型协方差

    它允许方法返回比基类型中声明的类型更派生的类型,例如

    public interface ISomeInterface
    {
        object GetValue();
    }
    
    public class SomeClass : ISomeInterface
    {
        public string GetValue() { return "Hello world"; }
    }
    

    这在 Java 中受支持,但在 C# 中不受支持。以上将无法编译,因为SomeClass.GetValueis stringnot的返回类型object

    请注意,您不能仅基于返回类型重载方法,即以下内容无效:

    public class SomeClass
    {
        public int GetValue() { return 1; }
        public string GetValue() { return "abc"; }
    }
    

    您可以使用接口做类似的事情,尽管您需要明确地实现它们以消除歧义:

    public interface IValue<T> { T GetValue(); }
    public class SomeClass : IValue<int>, IValue<string>
    {
        string IValue<string>.GetValue() { return "abc"; }
        int IValue<int>.GetValue() { return 1; }
    }
    

  • 如果名称相同但参数不同,则这是方法重载。这是一种形式的多态性(ad-hoc polymorphism)。重载在编译类型中静态解决(除非您dynamic在这种情况下使用它们被推迟到运行时)。

    您可以重载参数的数量及其类型,因此以下都是有效的:

    public void DoSomething(int value) { }
    public void DoSomething(string value) { }
    public void DoSomething(int value, string value) { }
    

    请注意,您可以更改这些方法的返回类型 - 方法不仅可以仅根据其返回类型进行重载,而且如果它们的参数列表不同,它们可能会有所不同。

  • 这又是返回类型协方差,在 C# 中不受支持。

  • 于 2013-03-12T13:28:49.510 回答
    13

    在 C# 中,你不能有类似的方法

    int Foo() { return 1; }

    void Foo() { return; }

    它们的变化必须不止返回类型。

    如果论点不同,那么你很高兴。

    int Foo(string x) { return 1; }

    void Foo(double x) { return; }

    于 2013-03-12T13:33:11.757 回答
    7

    尽管 C# 不支持返回类型协方差,但可以通过使用显式实现和方法隐藏来模拟它。这是在 ADO.NET API 中彻底使用的模式。

    例如:

    public interface ISomeValue { }
    public abstract class SomeValueBase : ISomeValue { }
    public class SomeValueImpl : SomeValueBase { }
    
    public interface ISomeObject { ISomeValue GetValue(); }
    
    public abstract class SomeObjectBase : ISomeObject
    {
        ISomeValue ISomeObject.GetValue() { return GetValue(); }
        public SomeValueBase GetValue() { return GetValueImpl(); }
    
        protected abstract SomeValueBase GetValueImpl();
    }
    
    public class SomeObjectImpl : SomeObjectBase
    {
        protected override SomeValueBase GetValueImpl() { return GetValue(); }
        public new SomeValueImpl GetValue() { return null; }
    }
    

    通过这样做,调用的最终结果GetValue()是它将始终匹配最具体的可用类型。

    于 2013-03-12T13:43:22.637 回答
    6

    是的,可以有多个方法具有相同的签名但不同的返回类型,使用显式接口实现,如下所示:

    public interface I {
      int foo();
    }
    
    public class C : I {
      double foo() { return 2.0; }
      int I.foo() { return 4; }
    }
    
    于 2013-03-12T13:42:19.013 回答
    2

    由于这是一个面试问题,您可以稍微回答一下。

    严格来说,不同返回类型和相同签名的方法是不可能的。但是,从广义上讲,有许多方法可以实现具体运行时返回类型不同的方法。

    一种是使用泛型参数。另一个是返回具有多个实现的接口或超类。或者,您可以返回一个对象,该对象可以转换为任何东西。

    正如许多人提到的,您还可以使用“new”关键字在子类中返回相同方法的派生类型。

    于 2013-03-12T13:59:46.833 回答
    0

    是的,您可以使用相同的方法、相同的参数(需要自定义)和不同的返回值。

    只需遵循以下代码,它可能会对您有所帮助。

    public class myClass
    {
        public int myReturn() { return 123; }
        public string myReturn(string temp = null) { return "test"; }
    }
    

    问题是,它需要参数来执行函数,但你仍然可以忽略参数,因为你有string temp = null可选参数,也就是说你仍然调用带有或不带参数的函数。

    于 2013-07-07T18:54:03.587 回答
    0

    我最近遇到了这个确切的问题,因为我正在解析具有各种类型的配置文件,这些类型都使用标准的 config.Parse(string settingName) 类型接口。

    第一种解决方案通用方法:

    T Parse<T> (string settingName)
    {
        T Result;
        doParsing...
        return T;
    }
    

    我真的不喜欢这个,因为它涉及明确指定正在使用的类型,例如someSetting = Parse<float>("param");

    所以我使用的解决方案是多余的,但在我看来更干净:

    T Parse<T> (string settingName, out T result)
    {
        doParsing...
        return T;
    }
    

    out 变量和 return 是相同的,所以它有点多余,但它使我认为是一个更干净的接口:

    setting = Parse("intparam", out setting);
    

    并且您获得的方法仅因返回类型而异,因此会产生轻微的冗余成本。最重要的是,如果您的数据类型发生变化,例如从双精度数变为浮点数,那么您一切都将继续正常工作,而使用第一个解决方案,您最终会得到无法隐式转换错误。

    于 2014-05-29T07:53:52.933 回答
    0

    您可以使用dynamic返回类型:

    于 2015-12-09T09:02:28.740 回答
    -1

    你可以做到这一点界面

       public interface IMyInterface
    {
        int Metoda1()enter code here`;
    }
    public class MyClass : test.IMyInterface
    {
        public IMyInterface Metoda1()
        {
            return new MyClas();
        }
        int test.IMyInterface.Metoda1()
        {
            return 1;
        }
    }
       static void Main(string[] args)
        {
            MyClass instance = new MyClass();
            IMyInterface inst = instance.Metoda1();
         /*   IMyInterface ints2 = inst.Metoda1(); //will not compile*/
            Console.WriteLine(inst.GetType().ToString()); ;
            object inst3 = inst.Metoda1();
            Console.WriteLine(inst3.GetType().ToString());
        }
    
    于 2015-11-12T23:48:04.003 回答