即使在派生类中,基类方法也可以返回吗?

时间:2011-10-17 19:03:01

标签: c# derived-class

我希望能够在C#基类中拥有一个方法,可以在几个派生类的对象上调用,返回对象本身,让CLR知道对象的实际类型 - ie ,适当的派生类型。 有人可以建议一种方法吗?其他当然,还有C#没有的返回类型协方差。

这样的东西,除了Method()的返回类型应该是派生类的类型,而不是基类:

public abstract class Base { 
    public Base Method() { return this; }
}

public class Derived1: Base { ... }

public class Derived2: Base { ... }

public class Main {
    public static int Main() {
        Derived1 d1 = new Derived1();
        Derived1 x = d1.Method();
        Derived2 d2 = new Derived2();
        Derived2 y = d2.Method();
    }
}

我只能想到两种方法来完成这项工作,我不喜欢其中任何一种:

  1. 将Method()的结果强制转换为期望的类型(例如Derived1 x = (Derived) d1.Method();)。但是施法者是魔鬼的工具,此外,该方法的目的是返回Derived1Derived2或......,而不是Base

    < / LI>
  2. 在基础中将Method()声明为抽象,并在每个派生类中单独实现。但这与分解常用方法的想法完全相反。除了返回类型之外,Method()在每种情况下都是相同的。

7 个答案:

答案 0 :(得分:12)

我相信您可以在C#4.0上使用dynamic关键字:

public abstract class Base { 
    public dynamic Method() { return this; }
}

public class Derived1: Base { ... }

public class Derived2: Base { ... }

public class Main {
    public static int Main() {
        Derived1 d1 = new Derived1();
        Derived1 x = d1.Method();
        Console.WriteLine(x.GetType()); // outputs Derived1
        Derived2 d2 = new Derived2();
        Derived2 y = d2.Method();
        Console.WriteLine(y.GetType()); // outputs Derived2
    }
}

答案 1 :(得分:11)

好的,我误解了这个问题。我认为OP 确实想要覆盖该方法。显然不是,所以泛型是前进的方向:

public abstract class Base<T> where T : Base<T>
{
    public T Method()
    {
        return (T) (object) this;
    }
}

public class Derived1 : Base<Derived1>
{
}

还有演员,但据我所知,不幸的是,这是不可避免的。你几乎肯定也想在构造函数中检查它:

public Base()
{
    if (this as T == null)
    {
        // throw some exception
    }
}

它很难看,但它会起作用......丑陋只限于基类。


原始回答

一种方法是将Method放入通用接口并明确实现:

public interface IFoo<T> {
    T Method();
}

public abstract class Base : IFoo<Base>
{
    Base IFoo<Base>.Method()
    {
        return this;
    }
}

public class Derived1 : IFoo<Derived1>
{
    public Derived1 Method()
    {
        // If you need to call the base version, you'll
        // need ((IFoo<Base>)this).Method()
        return this;
    }
}

这不好,但它会起作用......在可能的情况下,我想我会尽量避免需要它,说实话。 (是的,我在实现协议缓冲时遇到了类似的情况。这很烦人。)

答案 2 :(得分:8)

似乎有很多方法可以实现这一目标: 也可以使用扩展方法。
这样做的好处是允许你使用你不拥有的类,而你只需要执行一次,而不是每次派生/基类。 这将完全符合您的要求。

public class BaseClass
{

}
public class DerivedClass: BaseClass
{

}
public static class BaseClassHelpers
{
    public static T Method<T>(this T b) where T : BaseClass
    {
        return b;
    }
}    

正在使用中:

DerivedClass d = new DerivedClass();
DerivedClass dd = d.Method();
Console.WriteLine(dd.GetType());

导致控制台:

DerivedClass

答案 3 :(得分:5)

还有泛型但没有界面:

public abstract class Base<T> where T : Base<T>
{
    public virtual T Method()
    {
        return (T) this;
    }
}

public class Derived1 : Base<Derived1>
{
    public override Derived1 Method()
    {
        return base.Method();
    }
}

public class Derived2: Base<Derived2> { }

public class Program {
public static int Main() {
    Derived1 d1 = new Derived1();
    Derived1 x = d1.Method();
    Derived2 d2 = new Derived2();
    Derived2 y = d2.Method();
    return 0;
}

答案 4 :(得分:1)

这是一个没有投射的解决方案

public abstract class Base<T> where T : Base<T>
{
    public T Method()
    {
        return ThisDerived;
    }

    // It is worth to do this if you need the "this" of the derived class often in the base class
    protected abstract T ThisDerived { get; }
}

public class Derived1 : Base<Derived1>
{
    protected override Derived1 ThisDerived{ get { return this; } } 
}

public class Derived2 : Base<Derived2>
{
    protected override Derived2 ThisDerived { get { return this; } }
}

答案 5 :(得分:1)

如果您的方法具有类型T的参数,则不需要显式通用参数。

public class Base
{
    public T Method<T>()where T: Base
    {
        return (T)this;
    }
}

public class Derived1 : Base { }
public class Derived2 : Base { }

Derived1 d1 = new Derived1();
Derived1 x = d1.Method<Derived1>();
Derived2 d2 = new Derived2();
Derived2 y = d2.Method<Derived2>();

答案 6 :(得分:0)

有一种非常简单的方法可以使用new关键字和隐藏签名来实现所需的结果:

class Base
{
    public virtual Base Method () { return this ; }
}

class Derived1: Base 
{ 
    public new Derived1 Method () { return this ; }
}

class Derived2: Base
{
    public new Derived2 Method () { return this ; }
}