views:

405

answers:

3

Is it possible to enumerate which types that is "available" in a generic constraint?

T MyMethod<t>() where T : int, double, string

Why I want to do this is that I have a small evaluator engine and would like to write code like this:

bool expression.Evaluate<bool>();

or

int expression.Evaluate<int>();

but i want to prohibit

MyCustomClass expression.Evalaute<MyCustomClass>();
A: 

No, you can't.

You can add following generic constraint:

T MyMethod<T>() where T : struct {}

and than:

bool expression.MyMethod<bool>(); //OK

int expression.MyMethod<int>(); //OK

string expression.MyMethod<string>(); //failes, string is reference type

struct MyStruct {}

MyStruct MyMethod<MyStruct>(); //OK! MyStruct is value type

class MyCustomClass {}

MyCustomClass MyMethod<MyCustomClass>(); //FAILES! MyCustomClass is reference type

But you can add compile time constraint to int and string simultaneously.

Sergey Teplyakov
+3  A: 

It is not possible to restrict a generic argument to specific types.

As a workaround, you could provide plain old overloads and forward the method calls to a common implementation:

public class Expression {

    public bool Evaluate() {
        return Evaluate<bool>();
    }

    public int Evaluate() {
        return Evaluate<int>();
    }

    private T Evaluate<T>() {
        return default(T);
    }
}

On the other hand, have you thought about encoding the type the expression evaluates to in the Expression type? E.g.

public abstract class Expression<T> {

    public abstract T Evaluate();
}

public sealed class AddExpression : Expression<int> {

    public AddExpression(Expression<int> left, Expression<int> right) {
        this.Left = left;
        this.Right = right;
    }

    public Expression<int> Left { get; private set; }

    public Expression<int> Right { get; private set; }

    public override int Evaluate() {
        return this.Left.Evaluate() + this.Right.Evaluate();
    }
}
dtb
Once again thanks, this is even better solution than the one I thought of.
Marcus
+4  A: 

If you have a small number of possibilities for the generic type argument then the method is not truly generic. The point of generics is to allow parameterization of types and methods so that you can create infinitely many different such types and methods on demand. If you only have three possible types then write three methods. That is, create overloads, don't use generics.

Eric Lippert