Перегрузка общего интерфейса для методов? - PullRequest
3 голосов
/ 02 июня 2009

Есть ли хороший, общий способ сделать следующее, не прибегая к второму методу или большому количеству приведений - я хочу, чтобы API был как можно более легким, и мне кажется, что это нормально для OO:

class Foo
{
  public T Bar<T>() where T: IAlpha
  {
    /* blahblahblah */
  }

  public T Bar<T>() where T: IBeta
  {
    /* blahblahblah */
  }
}

interface IAlpha
{
  string x {set;}
}

interface IBeta
{
  string y {set;}
}

спасибо

Ответы [ 2 ]

7 голосов
/ 02 июня 2009

Вы не можете перегружать метод только возвращаемым значением (общим или нет). Кроме того, было бы невозможно разрешить вызовы к Bar, поскольку объект может реализовывать как IAlpha, так и IBeta, поэтому это невозможно при перегрузке.

public class AlphaBeta : IAlpha, IBeta
{
    string x {set;}
    string y {set;}
}

// too ambiguous
AlphaBeta parkingLot = myFoo.Bar<AlphaBeta>();

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

class Gar
{
    public string Foo()
    {
        return "";
    }

    public int Foo()
    {
        return 0;
    }
}

К сожалению, вашим лучшим решением будет использование менее общего решения. Шаблон команд здесь может вам пригодиться.

public class Foo
{
    private readonly static Dictionary<Type, Command> factories =
        new Dictionary<Type, Command>();

    static Foo()
    {
        factories.Add(typeof(IAlpha), new AlphaCreationCommand());
        factories.Add(typeof(IBeta), new BetaCreationCommand());
    }

    public T Bar<T>()
    {
        if (factories.ContainsKey(typeof(T)))
        {
            return (T) factories[typeof(T)].Execute();
        }
        throw new TypeNotSupportedException(typeof(T));
    }
}

// use it like this
IAlpha alphaInstance = myFoo.Bar<IAlpha>();
IBeta betaInstance = myFoo.Bar<IBeta>();

Другим способом реализации Bar, который позволяет вам вызывать его без явного объявления типа (в ваших угловых скобках), является использование параметра out. Однако я бы этого избегал, так как из-за 100% выходных параметров воняло плохим дизайном.

public void Bar<T>(out T returnValue)
{
    if (factories.ContainsKey(typeof(T)))
    {
        returnValue = (T) factories[typeof(T)].Execute();
        return;
    }
    throw new TypeNotSupportedException(typeof(T));
}

// call it like this
// T is inferred from the parameter type
IAlpha alphaInstance;
IBeta betaInstance;
myFoo.Bar(out alphaInstance);
myFoo.Bar(out betaInstance);

Я исключил Command, AlphaCreationCommand, BetaCreationCommand и TypeNotSupportedException. Их реализация должна быть достаточно понятной.

С другой стороны, вы можете использовать Func вместо команд, но это заставляет вас реализовывать весь код реализации в Foo, который может выйти из-под контроля по мере роста вашей кодовой базы.

1 голос
/ 04 апреля 2011

Как насчет этого?

class Foo
{
  public void Bar<T>(Action<T> @return) where T: IAlpha
  {
    @return(new AlphaImpl());
  }

  public void Bar<T>(Action<T> @return) where T: IBeta
  {
    @return(new BetaImpl());
  }
}

interface IAlpha
{
  string x {set;}
}

interface IBeta
{
  string y {set;}
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...