views:

124

answers:

6

I have developed some extension methods for objects, which I don't want to be used/shown in intellisense for objects which implements IEnumerable. Conceptually I want something like as follows

public static T SomeMethod<T>(this object value) where T != IEnumerable
        {

        }

Is it possible to impose this kind of constraint anyway in C#?

Edit

Sorry, I put the question in a wrong way. I know the allowable constraints in C#, what I want to know is that if there is any other way to accomplish this?

+11  A: 

Just to confirm Øyvind's comment: there's no such constraint in C#. The only types of constraint are:

  • where T : struct (non-nullable value type constraint)
  • where T : class (reference type constraint)
  • where T : SomeClassName (conversion to a particular class constraint)
  • where T : ISomeInterfaceName (conversion to a particular interface constraint)
  • where T : U (conversion to another type parameter constraint)
  • where T : new() (parameterless constructor constraint)

Note that I've only separated out the specific class and interface constraints as the former is a primary constraint and the latter is a secondary constraint.

Jon Skeet
Is there is other shortcut way to accomplish this?
Anindya Chatterjee
@Anindya: There is no way of doing this at compile-time, short or long. You could throw an exception at execution time, but it's pretty nasty to do so.
Jon Skeet
@Jon Skeet: Quite nasty indeed :) And it won't help his goal of removing the extension method from IntelliSense either.
Øyvind Bråthen
There's also the naked constraint: `where T : K` - for when you want relationships between parameters `T` and `K` of a generic type.
LBushkin
@LBushkin: True - will add that.
Jon Skeet
A: 

This is not possible.

SLaks
+1  A: 

This is not supported. Legal constraints are listed here.

Steve Townsend
A: 

As others mentioned what you want to do isn't going to work, but, you can look at what types of objects you want to support and limit it to some class/interface that they have in common, or you may just need to ditch the generic part and write several extension methods, so you can disallow IEnumerable.

James Black
A: 

You can't, and I agree it's a nuisance, though what I've found myself wanting is not so much what you are looking for, as overriding on the basis of the constraint (so that I could e.g. have a class and a struct version of the same method or class, and have the appropriate one used as applicable).

There are two cases where we can get by well.

One is where our reason for not wanting an extension method to be used is that it's already supplied as an instance method. In fact we get this for free; instance methods are always used instead of extension methods (though a derivedClass.method() wont' be used when you call baseClass.method() if it only exists in derivedClass).

The other case is runtime selection:

public static T SomeMethod<T>(this object value) where T != IEnumerable
{
  if(typeof(T).GetInterface("IEnumerable") != null)
  {
    //behaviour appropriate for IEnumerable
  }
  else
  {
    //other behaviour.
  }
}

It's not ideal, especially if the only "behaviour appropriate for IEnumerable" is to throw an exception, but it can be enough sometimes.

Jon Hanna
What's up with typeof(T).GetInterface("IEnumerable") != null . Is is or as not more clear?
Esben Skov Pedersen
@Esben, Borrowed from my thinking on something else, where I had to deal with the type separately from the object. Yes, `is`or `as` would serve fine and be a lot clearer.
Jon Hanna
A: 

You can do something like this, but only for types that you control.

Say you want to have a method like this:

public static class XmlSerializableExtension {   
  public static string ToXml(this object self) { 
    // ...
  }
}

But you don't want to pollute every object with it, only a subset of your classes.

You can achieve it like this:

public interface MXmlSerializable { } 
public static class XmlSerializable {   
  public static string ToXml(this MXmlSerializable self) {
    // ...
  }
}

Now, you mark the classes that you want this method to apply to with the "mixin" interface:

public class MyClass : MXmlSerializable { 
  // ...
} 

And it will only appear in intellisense for these classes.

Jordão