Как вызвать метод с общим ограничением, используя параметр типа без ограничения? - PullRequest
0 голосов
/ 23 ноября 2018

Допустим, у меня есть метод:

public void ExampleMethod<T>(T x) where T : struct // or new()
{
    // example usage, similar to what's actually happening
    var z = (T)Enum.Parse(typeof(T), privateFieldOfTypeString);

    // do something depending on values of x and z
    // possibly using other methods that require them being enums

    // or in case of the new() constraint:
    // var t = new T() and do something together with x
}

, и я хочу использовать его следующим образом:

public void CallerMethod<S>(S y)
{
    if (typeof(S).IsEnum) // or some other invariant meaning that `S` is "new()able"
    {
        ExampleMethod(y); // won't compile
    }
}

Итак, во время выполнения я знаю, что S удовлетворяетограничение для ExampleMethod<T>.Я знаю, что это можно назвать с помощью отражения, что-то вроде:

this
    .GetType()
    .GetMethod(nameof(ExampleMethod<object>))
    .MakeGenericMethod(typeof(S))
    .Invoke(this, new object[] { y });

Возможно ли это без отражения?

Примечание: это упрощенный код из реального примера, и, очевидно, я не контролирую сигнатуры этих методов, поэтому ответы «добавить ограничение к CallerMethod»и "удалить ограничение из ExampleMethod" недопустимо.

Да, все это должно быть переработано, чтобы не возникала вся проблема.Но, как это часто бывает в реальной жизни, «все это» слишком велико, слишком тесно и слишком рискованно, чтобы переписывать.Некоторые требования изменились неожиданным образом - отсюда и очевидный запах кода, который я пытаюсь минимизировать, пряча его в одном неприятном месте.

Ответы [ 4 ]

0 голосов
/ 23 ноября 2018

Вы можете использовать перегрузку оператора;определить несколько явных версий CallerMethod, которые все могут успешно выполнить последующий вызов ExampleMethod

CallerMethod(Enum1 value) { ExampleMethod(value); }
CallerMethod(Enum2 value) { ExampleMethod(value); }
CallerMethod(Enum3 value) { ExampleMethod(value); }

и т. д.

Если существует большое количество растущих типов, которым требуетсяверсия CallerMethod вы можете написать шаблон T4 для генерации класса partial со всеми реализациями.

0 голосов
/ 23 ноября 2018

В вашем конкретном случае вы можете просто привести к int.

public void CallerMethod<S>(S y)
{
    if (typeof(S).IsEnum)
    {
        ExampleMethod((int)y);
    }
}
0 голосов
/ 23 ноября 2018

Если типы перечислений известны, одной из возможностей, хотя и многословной, было бы преобразование в известные типы.

Например, в качестве отправной точки,

public void CallerMethod<S>(S y) {
    if (typeof(S).IsEnum) {
        if (y is KnownEnum) {
            var z = (KnownEnum)Enum.Parse(typeof(S), y.ToString());
            ExampleMethod(z);
        }
        if (y is KnownEnum2) {
            var z = (KnownEnum2)Enum.Parse(typeof(S), y.ToString());
            ExampleMethod(z);
        }
        //...
    }
}
0 голосов
/ 23 ноября 2018

Вы можете использовать dynamic:

if (typeof(S).IsEnum)
{
    ExampleMethod((dynamic)y);
}
...