简体   繁体   中英

Generic interface overloading for methods?

Is there a good, generic, way to do the following without resorting to a second method or lots of casts - I want to keep the API as light as possible and it seems ok to me OO-wise:

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

thanks

You can't overload a method by return value only (generic or not). Additionally, it would be impossible to resolve calls to Bar , since an object could implement both IAlpha and IBeta , so this is not possible using overloading.

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

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

The below will also not work, because the methods only differ by return type

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

    public int Foo()
    {
        return 0;
    }
}

Unfortunately, your best solution will be to use a less generic solution. The command pattern might serve you well here.

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

Another way of implementing Bar which allows you to call it without explicitly declaring the type (in your angled brackets) is to use an out parameter. I'd avoid it, however, since out parameters in 100% managed usually stink of bad design.

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

I excluded Command , AlphaCreationCommand , BetaCreationCommand , and TypeNotSupportedException . Their implementation should be fairly self explanatory.

Alternately, you can use Func instead of Commands, but this forces you to implement all of your instantiation code in Foo which can get out of hand as your code base grows.

How about this?

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM