2015-03-20 2 views
1

Вот простой класс и производный класс:метод, который возвращает экземпляр подкласса

class A { public int val; } 

class B : A { } 

Я хотел бы метод Inc, который работает на обоих A и B экземпляров, которая возвращает новый экземпляр с 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 - и b0.val - .

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>(); 

Есть ли способ, чтобы идти по пути метода член без квалифицировать тип?

+0

Ожидаете ли вы 'var b0' -' B b0', или вы в порядке с 'A b0'? Если более поздний клон-раствор будет носителем, вероятно, вы хотите.Я не думаю, что вы можете добиться надежного 'B b0' (см. Комментарий p.s.w.g к RagtimeWilly's [ответ] (http://stackoverflow.com/a/29158330/477420)). –

+0

@AlexeiLevenkov результат 'b.Inc()' должен быть типа 'B' – dharmatech

+1

Рассмотрите возможность редактирования сообщения с этой важной частью информации ... И выясните, что вы ожидаете от' A b = new B {val = 20 }; ??? b0 = b.Inc(); ' –

ответ

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 }; 
    } 
} 
+0

Почему бы не использовать переопределение в классе B? – liuzhidong

+0

Он не будет компилироваться. Вы получите сообщение о том, что «невозможно изменить тип возвращаемого значения при переопределении» – RagtimeWilly

+0

Сначала это было уродливо, теперь это еще хуже. – zerkms

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; 
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); 

Но это не ответ, так как вы хотели метод члена. Я предпочитаю использовать метод расширений.

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()); 
} 
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); 
Смежные вопросы