13

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>();
Marcus
  • 1,866
  • 1
  • 20
  • 33
  • Have a look at this question: http://stackoverflow.com/questions/32664/c-generic-constraint-for-only-integers – M4N Mar 06 '10 at 09:15
  • 1
    Are you sure that `Evaluate()` and `Evaluate()` has the same implementation? If your method only works with a specific list of types, odds are that your method isn't as generic as you think. – dtb Mar 06 '10 at 09:27
  • 2
    @dtb: Thanks for the tip, i think that thats my real problem, i guess the lazyness is grabbing me, only want to write one method. :) – Marcus Mar 06 '10 at 09:30

3 Answers3

11

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
  • 647,829
  • 179
  • 1,238
  • 2,067
  • 2
    Not maintainable. If "generic" isn't the right terminology, then make a different construct with the right one. –  Mar 03 '13 at 06:50
  • Even when there are a discrete number of possibilities, using generics may sometimes be advantageous for "middle" layers of an application. For example, suppose one wishes to write a routine to perform some algorithm upon the numbers in an array, and the algorithm only depends upon being able to compare two elements or take the sum of two elements. If one had a static method `T ComputeSum(T x, T Y)` which worked for any numeric primitive type, using generics would make it possible for a single method in source code to perform the algorithm on any supported type. – supercat Apr 29 '13 at 16:59
6

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

As a workaround, you could provide a method for each type and forward the method calls to a common implementation:

public class Expression {

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

    public int EvaluateToInt32() {
        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
  • 213,145
  • 36
  • 401
  • 431
1

No, you can't.

You can add the following generic constraint:

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

And then:

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

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

string expression.MyMethod<string>(); //fails! string is a reference type

struct MyStruct {}

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

class MyCustomClass {}

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

But you can't add compile time constraints for int and string simultaneously.

internets
  • 9
  • 2
Sergey Teplyakov
  • 11,477
  • 34
  • 49