2012-02-20 4 views
7

Возможно ли создать абстрактный метод, который должен возвращать экземпляр производного класса? Я могу это сделать:Абстрактный метод, возвращающий экземпляр производного класса

abstract class Base 
{ 
    public abstract Base GetObj(); 
} 

class Derived : Base 
{ 
    public Derived() { } 

    public override Base GetObj() 
    { 
     return new Derived(); 
    } 
} 

Но мне было интересно, если есть способ сделать это таким образом, что Derived::GetObj() вынужден вернуть Derived?

Спасибо.

+1

См. Http://blogs.msdn.com/b/ericlippert/archive/2011/02/03/curiouser-and-curiouser.aspx для подводных камней и проблем, которые необходимо учитывать. –

+0

Спасибо за ссылку. Интересное чтение. – Eric

ответ

16

Использование дженериков должны сделать это возможным:

abstract class Base<T> 
    where T : Base<T> 
{ 
    public abstract T GetObj(); 
} 

class Derived : Base <Derived> 
{ 
    public Derived() { } 

    public override Derived GetObj() 
    { 
     return new Derived(); 
    } 
} 

Можно даже упростить это еще более (если все производные экземпляры создаются с конструкторами по умолчанию):

abstract class Base<T> 
    where T : Base<T>, new() 
{ 
    public static T GetObj() 
    { 
     return new T(); 
    } 
} 

class Derived : Base<Derived> 
{ 
    public Derived() { } 
} 
+3

Обратите внимание, что это приводит к тому, что производный класс * first * возвращает себя. Второй производный класс затем может просто вернуть первый. –

+0

Спасибо, это похоже на то, что мне нужно. Я не думаю, что есть способ сделать это статическим методом? – Eric

+0

Да, метод может быть статическим, и в этом случае у вас есть завод. И сможет использовать 'Derived.GetObj()'. – Lukazoid

6

То, что вы есть почти, но не совсем точно абстрактная фабрика. Я сначала скажу, что вы должны оставить его разработчикам производных классов, чтобы понять это правильно или просто доверять им.

Другой ответ показал так называемый шаблон с любопытным повторяющимся шаблоном. Здесь вы используете базовый класс, который пытается использовать систему типов для обеспечения того, чтобы производные типы использовали себя на определенных позициях ввода или вывода.

public abstract class Foo<T> where T : Foo<T> 
public class Bar : Foo<Bar> 

Эта идея может работать на других языках. Он работает на C# только в том случае, если люди правильно его используют. С приведенным выше определением Бар теперь можно также получить

public class Baz : Foo<Bar> 

Это совершенно законно. Bar - это Foo<Bar>, что является обязательным условием для использования Базом. Ничто не требует, чтобы Баз фактически использовал Foo<Baz>.

Система типов в C# просто не может обеспечить выполнение того, что вы хотели бы применить. Даже с этим рисунком на месте вы все еще находитесь в том же положении, что и раньше. Вы все равно должны доверять разработчикам производных классов, чтобы сделать это правильно.

Для получения дополнительной информации по этой теме, вы можете прочитать this blog.

Смежные вопросы