С# общие ограничения

Можно ли перечислять типы, которые "доступны" в общем ограничении?

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

Почему я хочу это сделать, так это то, что у меня есть небольшой механизм оценки и хотел бы напишите код следующим образом:

bool expression.Evaluate<bool>();

или

int expression.Evaluate<int>();

но я хочу запретить

MyCustomClass expression.Evalaute<MyCustomClass>();

Ответы

Ответ 1

Невозможно ограничить общий аргумент конкретными типами.

В качестве обходного пути вы можете предоставить метод для каждого типа и перенаправить вызовы метода на общую реализацию:

public class Expression {

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

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

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

С другой стороны, подумали ли вы о кодировании типа, которое выражение выражает в типе выражения? Например.

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();
    }
}

Ответ 2

Если у вас есть небольшое количество возможностей для аргумента generic type, этот метод не является действительно общим. Точка дженериков состоит в том, чтобы разрешить параметризацию типов и методов, чтобы вы могли создавать бесконечно много разных типов и методов по требованию. Если у вас есть только три возможных типа, напишите три метода. То есть, создавайте перегрузки, не используйте дженерики.

Ответ 3

Нет, вы не можете.

Вы можете добавить следующее общее ограничение:

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

И затем:

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

Но вы не можете добавлять ограничения времени компиляции для int и string одновременно.