views:

65

answers:

3

Is there a way to apply several different csharp generic constraints to the same type where the test is OR rather than AND?

I have an extension method I want to apply to a subset of an interface, but there is no common interface or base class that only captures the classes I wish to target.

In the example below, I could write multiple methods each with a single constraint that all call the same Swim method, but I am wondering if there is a way to write one method with multiple non-intersecting constraints.

Eg

interface IAnimal
{
   bool IsWet { get; set; }
   bool IsDrowned { get; set; }
}

public static class SwimmingHelpers
{
    /*this is the psuedo effect of what I would like to achieve*/
   public static void Swim<T>(this T animalThatCanSwim) 
    where T: IAnimal, Human |
    where T: IAnimal, Fish |
    where T: IAnimal, Whale ....
}

FYI The actual scenario I am toying with is HTML elements that all implement an IElement interface but I want to target only elements where certain behaviours are valid in the HTML specification and no more specific common interface is implemented by them eg: elements that can have a readonly attribute.

A: 

There is no OR operator in generics.

But you can always introduce new interface to capture the subset of classes, ie. IReadOnly. This can be a marker interface that doesn't define any methods. Over time you might actually to find some usage for those new interfaces...

Jakub Konecki
I generally, using a new interface would be a way to go, but the OP can't do that as the types are from a third-party library.
0xA3
+3  A: 

Not with generics. You could, however, get what you want by defining plain overloads like this:

public static class SwimmingHelpers {
   public static void Swim(this Human animalThatCanSwim) {
      SwimInternal(animalThatCanSwim);
   }
   public static void Swim(this Fish animalThatCanSwim) {
      SwimInternal(animalThatCanSwim);
   }
   public static void Swim(this Whale animalThatCanSwim) {
      SwimInternal(animalThatCanSwim);
   }
   private static void SwimInternal(IAnimal animalThatCanSwim) {
      // do your work here, no duplication of the code needed
   } 
}
Lucero
+1  A: 

The reason it doesn't work that way makes sense when you consider the fact that generic constraints aren't there to enforce your intended use of the method. Rather, they are there to allow you to make certain assumptions about the type parameter. For example, by constraining the type to be IComparable, you know that you can call a Compare method even though the exact type is not known yet. Constraining a type with new() ensures that you can call a default constructor on the type. So if generic constraints allowed you to specify one constraint or another, you could not make those assumptions.

Josh Einstein