1

I want to extend the IEnumerable class but only for types that can be operated (int, decimal, single and double).

Is this doable? I don't see the way to restrict this:

public static class IEnumerableExtension
{
    public static decimal FindBestSubsequence<T> (this IEnumerable<T> source, out int startIndex, out int endIndex)
    {

    }
}

Thanks in advance.

Ignacio Soler Garcia
  • 21,122
  • 31
  • 128
  • 207

2 Answers2

3

You're looking for generic constraints but you can't constrain a type parameter to only be valid for a specific set of types. The closest you could come would be something like:

public static decimal FindBestSubsequence<T>
    (this IEnumerable<T> source, out int startIndex, out int endIndex)    
     where T : struct, IConvertible, IFormattable, IComparable<T>, IEquatable<T>,
     IComparable

... as those are all interfaces which each of those types implements. However, this wouldn't prevent, say, Int16 from being used as the type argument. Do you definitely not want it to be applicable for an IEnumerable<short>? What would go wrong if it were used for that?

You could have a set of non-generic public overloads, which then called to a constrained generic private method:

public static decimal FindBestSubsequence(this IEnumerable<decimal> source,
    out int startIndex, out int endIndex)
{
    return FindBestSubsequenceImpl(source, startIndex, endIndex);
}

public static decimal FindBestSubsequence(this IEnumerable<int> source,
    out int startIndex, out int endIndex)
{
    return FindBestSubsequenceImpl(source, startIndex, endIndex);
}

// etc

// Could constrain T more if it was useful in the method, but we know
// T will only be one of the types we want, because only this class can
// call this method
private static decimal FindBestSubsequence<T>
    (IEnumerable<T> source, out int startIndex, out int endIndex)    
     where T : struct
{
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Thanks Jon. The algorithm I'm writing can work on any numeric type and probably a struct that implements all these interfaces is numeric. – Ignacio Soler Garcia Mar 24 '12 at 16:34
  • @SoMoS: Not necessarily. `DateTime` would count, for example. Would that be a problem? In fact, if you only constrain `T` to the interfaces you need to implement the method (probably `IComparable`), what problems are you considering? – Jon Skeet Mar 24 '12 at 16:36
  • Well, it will execute over DateTime but the result won't have any sense. Maybe I can check the type on runtime and throw something. – Ignacio Soler Garcia Mar 24 '12 at 16:37
  • @SoMoS: Would it definitely not make sense? It would help if you could describe what you're implementing. Did you see my edited answer for another alternative? – Jon Skeet Mar 24 '12 at 16:39
  • @JonSkeet: I'm searching thru a sequence of numbers of find the subsequence that gives the maximum value when adding its values (they are + and - numbers). Therefor, executing the method over an unsigned value has no sense. – Ignacio Soler Garcia Mar 24 '12 at 16:45
  • @SoMoS: If you need to add values together, you'll need to work out how you're planning on doing that anyway - seeing as there's no generic way of doing that. (You could potentially do it using `dynamic`, potentially, as just one example.) – Jon Skeet Mar 24 '12 at 16:53
  • @JonSkeet: you're right, everyone implements the method Add but looks like they have no common base :\ ... still thinking. Bytheway I've found that what I need is to implement the maximum subarray problem (http://en.wikipedia.org/wiki/Maximum_subarray_problem). – Ignacio Soler Garcia Mar 24 '12 at 16:55
1

You can restrict to value types by using where T : struct

From MSDN:

where T: struct

The type argument must be a value type. Any value type except Nullable can be specified. See Using Nullable Types (C# Programming Guide) for more information.

Chris Gessler
  • 22,727
  • 7
  • 57
  • 83