返回子类实例的方法

时间:2015-03-20 02:06:03

标签: c# generics inheritance methods subclass

这是一个简单的类和派生类:

class A { public int val; }

class B : A { }

我喜欢方法Inc,它适用于AB个实例,它们返回一个val递增1的新实例。

解决此问题的一种方法是将Inc定义为扩展方法:

static class Extensions
{
    public static T Inc<T>(this T obj) where T : A, new()
    {
        return new T() { val = obj.val + 1 };
    }
}

这似乎有效。在以下示例中,a0.val 11 b0.val 21

var a = new A() { val = 10 };

var b = new B() { val = 20 };

var a0 = a.Inc();

var b0 = b.Inc();

我的问题是,有没有办法将Inc定义为A的直接成员并让它按上述方式运作?

如果我这样定义A

class A 
{ 
    public int val;

    public T Inc<T>() where T : A, new()
    {
        return new T() { val = val + 1 };
    }
}

然后,当我致电Inc时,我需要对该类型进行限定:

var a = new A() { val = 10 };

var b = new B() { val = 20 };

var a0 = a.Inc<A>();

var b0 = b.Inc<B>();

有没有办法去成员方法路线而不必限定类型?

5 个答案:

答案 0 :(得分:2)

如果没有在每个子类上实现new版本的方法,我认为不可能,例如:

class A
{
    public int val;

    public virtual A Inc()
    {
        return new A { val = val + 1 };
    }
}

class B : A
{
    public new B Inc()
    {
        return new B { val = val + 1 };
    }
}

答案 1 :(得分:2)

因此,您实际上想要为某些字段创建具有不同值的对象的克隆:

class A {
    public int val;
    protected virtual A CloneInternal() {
        return (A)MemberwiseClone();
    }
    public A Inc() {
        A a=CloneInternal();
        ++a.val;
        return a;
    }
}
class B:A {
    public new B Inc() {
        return (B)base.Inc();
    }
}
static void Main() {
    A a=new B();
    a=a.Inc();
    Console.WriteLine(a.GetType());
}

答案 2 :(得分:1)

    abstract class Base
    {
        public int val { get; set; }

        public virtual Base Inc() { return null; }
    }

    class A : Base
    {

        public override Base Inc()
        {
            return new A { val = val + 1 };
        }
    }

    class B : A
    {
        public override Base Inc()
        {
            return new B { val = val + 2 };
        }
    }

使用抽象基类可能更好....

Base bClass = new B();
B bInc = bClass.Inc() as B;

答案 3 :(得分:1)

我不认为这是可能的。您应该提供一个提示,以使编译器猜测T的正确类型。

您可以尝试使用静态方法:

public static T Inc<T>(T source) where T : A, new()
{
   return new T() { val = source.val + 1 };
}

然后,

var b = new B { val = 20 };
var b0 = A.Inc(b);

但这不是一个答案,因为你想要一个成员方法。我宁愿选择扩展方法。

答案 4 :(得分:1)

另一种方式

interface IInc
{
    int val { get; set; }

    IInc GetNew();

}

class A : IInc
{
    public int val
    {
        get;
        set;
    }

    public virtual IInc GetNew()
    {
        return new A();
    }

    public IInc Inc()
    {
        var newObj = GetNew();
        newObj.val++;

        return newObj;
    }
}

class B : A
{
    public override IInc GetNew()
    {
        return new B();
    }
}

并使用

 var a = new A() { val = 10 };
 var b = new B() { val = 20 };
 var a0 = a.Inc();
 var b0 = b.Inc();
 Console.WriteLine(a0.val);
 Console.WriteLine(b0.val);