3

2番目のメソッドや多くのキャストに頼ることなく、次のことを行うための優れた一般的な方法はありますか?

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

ありがとう

4

2 に答える 2

7

戻り値だけでメソッドをオーバーロードすることはできません (ジェネリックかどうかに関係なく)。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 を実装するもう 1 つの方法は、明示的に型を宣言せずに呼び出すことができるようにする (角かっこで) ことです。ただし、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);

CommandAlphaCreationCommandBetaCreationCommand、およびを除外しTypeNotSupportedExceptionました。それらの実装はかなり自明です。

別の方法として、コマンドの代わりに Func を使用することもできますが、これによりFoo、コード ベースが大きくなるにつれて手に負えなくなる可能性のあるすべてのインスタンス化コードを実装する必要があります。

于 2009-06-02T15:40:18.217 に答える
1

これはどう?

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;}
}
于 2011-04-04T11:59:57.183 に答える