Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to constrain a generic type parameter to String OR Array

In short: is it possible to define a generic method where the type parameter (T) is constrained to string or int[]? In pseudo-C#, what I want to do is:

public static int MyMethod<T> ( T arg1, T arg2 ) 
    where T : (has an indexer that returns an int) {
    // stuff with arg1[i], arg2[j], etc...
}

Note that in C#, due to the built-in string indexer (which returns a char) along with implicit conversion from char to int, the following expression means precisely the same thing whether source is a string or an int[]:

int someval = source[index];

Per the thread Constrain generic extension method to base types and string I realize I can't just make a list of unassociated types in the where T : x... constraint clause. Both int[] and string would comply with T: IEnumerable<int>, but IEnumerable<T> does not require implementers to have an indexer, which is exactly the common feature I am using from both types.

The purpose behind this is that I'm building some highly optimized string parsing and analyzing functions such as a fast implementation of the Damerau–Levenshtein distance algorithm. I've found that first converting my strings to arrays of int can sometimes yield significantly faster executions in repetitive character-by-character processing (as with the D-L algorithm). This is largely due to the fact that comparing int values is much faster that comparing char values.

The operative word is 'sometimes'. Sometimes it's faster to operate directly on the strings and avoid the cost of first converting and copying to arrays of int. So I now have methods that are truly identical except for the declarations.

Of course I can use dynamic, but the performance penalty from runtime checking completely destroys any gains made in the construction of the methods. (I did test it).

like image 590
Joshua Honig Avatar asked Jan 13 '12 21:01

Joshua Honig


People also ask

Is it possible to inherit from a generic type?

An attribute cannot inherit from a generic class, nor can a generic class inherit from an attribute.

What is generic type constraint?

A type constraint on a generic type parameter indicates a requirement that a type must fulfill in order to be accepted as a type argument for that type parameter. (For example, it might have to be a given class type or a subtype of that class type, or it might have to implement a given interface.)

What keyword allows you to put constraints on a generic type?

The where clause in a generic definition specifies constraints on the types that are used as arguments for type parameters in a generic type, method, delegate, or local function.

Can a generic class have multiple constraints?

Multiple interface constraints can be specified. The constraining interface can also be generic.


2 Answers

You cannot have a constraint that says “the type must have an indexer”.

However, you can have a constraint that says “the type must implement an interface that has an indexer”. Such an interface might be IList<char>, for example.

Unfortunately, string doesn’t implement IList<char>, so you would have to write a small wrapper class for it:

sealed class StringWrapper : IList<char>
{
    public string String { get; private set; }
    public StringWrapper(string str) { String = str; }
    public static implicit operator StringWrapper(string str)
    {
        return new StringWrapper(str);
    }

    public char this[int index]
    {
        get { return String[index]; }
        set { throw new NotSupportedException(); }
    }

    // Etc.... need to implement all the IList<char> methods
    // (just throw NotSupportedException except in the ones that are trivial)
}

And then you can declare your method like this:

public static TElement MyMethod<TCollection, TElement>(TCollection arg)
    where TCollection : IList<TElement>
{
    return arg[0];
}

[...]

MyMethod<StringWrapper, char>("abc")     // returns 'a'
MyMethod<int[], int>(new[] { 1, 2, 3 })  // returns 1
like image 111
Timwi Avatar answered Oct 16 '22 13:10

Timwi


No, C# does not allow you to create a "composite" constraint like that.

The expression you show does mean the same thing, but you can't use that fact to your advantage. C# generics resemble C++ templates syntactically, but they work completely differently, so the fact that the indexer does the same thing ends up being irrelevant.

You could, of course, just create the two overloads with the specific types you need, but that does mean some annoying copy & paste. Any attempts at abstracting this to avoid repetition will cost you performance badly.

like image 27
Roman Starkov Avatar answered Oct 16 '22 12:10

Roman Starkov