views:

263

answers:

4

I would like to have a delegate that is constrained to returning one of two types; an ActionResult or a string. Is this possible?

+5  A: 

No, it's not possible (at least not in C# 4 and below). There's no support for "or" constraints on generic type parameters.

There's also no constraint that restricts a type argument to be an exact type. All constraints restrict the base types of the type argument. They cannot restrict you from inheriting from them.

Mehrdad Afshari
Fyi: the type `string` cannot be used as a constrained at all: it is a sealed class and sealed classes are prohibited for use in generic type arguments.
Abel
Abel: That's a special case of my second point (no "exact type" constraint). Generics are fundamentally designed to make your code more "general". Restricting the type argument to a single type, by definition, contradicts the fundamental point of existence for generics.
Mehrdad Afshari
Never thought of it like that, but that makes perfect sense. Thanks for the additional explanation :)
Abel
PS: you mention "or"-constraints, but in a way, when you give a list of interfaces, aren't those both "or" and "and" constraints in one?
Abel
@Abel: You can mention a list of types. If you do, you'll be constraining the type argument to inherit/implement all of those types.
Mehrdad Afshari
+2  A: 

No, it's not. Besides, what would be the benefit of doing this? Unless the two types have something in common, then there's nothing that you can really do with the return type.

Consider some code that calls the delegate:

var returnValue = someDelegate();

What type is var in this case? The only common ancestor of string and ActionResult is object, so that's all you can get from it. From a static typing point of view, you may as well just declare the return type as object.

Will Vousden
Isn't a constraint to one of two types better than the all encompassing object? I shall attempt to implement my solution using object. Appreciate your answer!
Ben Aston
The calling code still doesn't know what the type is, though, so it'll still have to explicitly check the type before it can actually do anything with it. This doesn't really offer any benefit over a non-generic delegate, other than that you'll have to add a condition that deals with unexpected types.Generics are intended to maintain static typing on classes/delegates/methods that don't deal with any particular type.
Will Vousden
A: 

Like Zakalwe, I also don't see any point in doing this, but..

You could define two overloaded methods which accept a Func<string> and a Func<ActionResult> respectively. A private method could take Delegate and do further things with it.

Oliver Hanappi
+2  A: 

As other answers have explained, you cannot do this, however you could work around it by passing different continutations for each return type:

public delegate void MultiPathDelegate(Action<ActionResult> arAction, Action<string> strAction);

So checking the return type occurs in the delegate instead of the caller.

Lee