Интерфейс для метода, который возвращает его собственный тип

У меня есть ситуация, где у меня есть класс

class Foo
{
    Foo Bar()
    {
        return new Foo();
    }
}

Теперь я бледный итог создаю интерфейс для него

class IFoo
{
    ??? Bar();
}

Что должно быть вместо вопросительных знаков? Каждый класс должен возвратить свой собственный тип, не Foo.

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

Это - то, как я использую его позже

class GenericClass<T> where T : IFoo
{ 
    T foo = new T();
    T item = foo.Bar();
}
8
задан Andrey 15 June 2010 в 14:31
поделиться

7 ответов

Вы спрашиваете:

Приведенные ниже решения работают, но не выглядят чистыми. Я не понимаю, почему я должен указывать один и тот же класс дважды, а для текущего типа нет ничего похожего на «this»

. Причина, по которой вы должны указывать его дважды, заключается в том, что в C # отсутствует необходимая функция. Вам нужно что-то вроде этого:

interface IFoo
{
    IFoo Bar();
}

class Foo : IFoo
{
    Foo Bar() // should work since Foo is an IFoo, but it's not supported by C#
    {
        return new Foo();
    }
}

С точки зрения безопасности типов это должно работать (это называется ковариацией возвращаемого типа ). Фактически, другие языки программирования, такие как C ++ или Java, поддерживают это, см. этот пример в Википедии . К сожалению, ковариация возвращаемого типа не поддерживается C # (даже C # 4.0, который ввел ковариацию для универсальных шаблонов), поэтому вы должны использовать «обходной путь для универсальных шаблонов», показанный в других ответах.

Ковариантные возвращаемые типы, а также тип «this» - это предлагаемые функции для новых версий C #:

11
ответ дан 5 December 2019 в 06:36
поделиться

Вы можете добавить общий тип и ограничить его, используя тип интерфейса:

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

Вы бы реализовали это следующим образом:

public class Foo : IFoo<Foo>
{
    public Foo Bar()
    {
        return new Foo();
    }
}

public class Cheese : IFoo<Cheese>
{
    public Cheese Bar()
    {
        return new Cheese();
    }
}

Обновите , если вас никогда не заботит конкретный тип возвращаемого значения Foo, вы можете сделать следующее:

public interface IFoo
{
    IFoo Bar();
}

Что реализовано как:

public class Foo : IFoo
{
    public IFoo Bar()
    {
        return new Foo();
    }
}

Затем в вашем универсальном классе:

public class GenericClass<T> where T : class, IFoo, new()
{
    public T Rar()
    {
        T foo = new T();
        T item = foo.Bar() as T;
        return item;
    }
}

GenericClass .Rar (); будет конкретной реализацией Foo .

8
ответ дан 5 December 2019 в 06:36
поделиться

Я думаю, что реальный вопрос: зачем вам нужен производный тип в интерфейсе? Интерфейс как раз по этой причине - абстрагирование от конкретных классов. Если это просто для удобства, так что вам не нужно приводить к Foo после вызова Bar (), вы можете реализовать интерфейс явно:

interface IFoo
{
    IFoo Bar();
}

class Foo : IFoo
{
    public Foo Bar()
    {
        return new Foo();
    }

    IFoo IFoo.Bar()
    {
        return Bar();
    }
}

Задайте себе вопрос: зачем вы вводите интерфейс, когда вам нужен конкретный тип?

4
ответ дан 5 December 2019 в 06:36
поделиться
public interface IFoo<T>
{
    T Bar();
}

Ваша реализация будет выглядеть так:

class Foo : IFoo<Foo>
{
    Foo Bar()
    {
        return new Foo();
    }
}

class Baz : IFoo<Baz>
{
    Baz Bar()
    { 
        return new Baz(); 
    }
}
0
ответ дан 5 December 2019 в 06:36
поделиться

Вам нужно сделать интерфейс общим, например так:

interface IFoo<TClass> where TClass : IFoo<TClass>, class {
    TClass Bar();
}
0
ответ дан 5 December 2019 в 06:36
поделиться

Не уверен, чего вы пытаетесь добиться, но это можно сделать так:

interface IFoo<T>
{
    T Bar();
}



   class Foo:IFoo<Foo>
    {

        #region IFoo<Foo> Members

        public Foo Bar()
        {
            return new Foo();
        }

        #endregion
    }

Или вот так:

    interface IFoo
    {
        IFoo Bar();
    }

class Foo : IFoo
    {

        #region IFoo Members

        public IFoo Bar()
        {
            return new Foo();
        }

        #endregion
    }
0
ответ дан 5 December 2019 в 06:36
поделиться

Для этого можно использовать абстрактный базовый класс плюс явную реализацию членов. Сначала объявите свой интерфейс следующим образом:

interface IFoo
{
    IFoo Bar();
}

Затем объявите общий абстрактный класс, который реализует IFoo в явном виде, а также объявите абстрактный метод, который как бы "перегружает" Bar(), но в общем виде:

abstract class BaseFooImpl<T> : IFoo where T : BaseFooImpl
{
    public abstract T Bar();

    IFoo IFoo.Bar()
    {
        return Bar(); // this will call the abstract Bar()
    }
 }

Теперь определите свои конкретные классы следующим образом:

class ConcreteFoo : BaseFooImpl<ConcreteFoo>
{
   public override ConcreteFoo Bar()
   {
      return this; // for example, of course.
   }
}

Преимущество этого подхода в том, что вы всегда можете использовать негенеративные ссылки IFoo для хранения конкретных экземпляров. Если вы сделаете свой интерфейс общим, вы не сможете, например, объявить следующее:

IFoo mammalInstance, fishInstance; // Instead of IFoo<Mammal> mammalInstance; IFoo<Fish> fishInstance;
List<IFoo> manyInstances; // Instead of List<IFoo<IFoo>>, which doesn't even work AFAIK
2
ответ дан 5 December 2019 в 06:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: