Добавление методов расширения для всех перечислений, а не только для определенного вида - PullRequest
0 голосов
/ 16 мая 2018

Редактировать : Этот пост не является дубликатом, другие решения не позволяют использовать побитовые операторы.

Я хочу сделать что-то вроде этого:

public static class EnumExt
{
    public static enum AddFlag(this enum e, enum flag) => e |= flag;
}

Так что я могу использовать это так:

Color color = Red;
color.AddFlag(Color.Dark);

Это немного легче читать. И Я хочу, чтобы этот единственный метод работал для всех значений перечисления, вместо того, чтобы делать переопределение для каждого, с которым я планирую работать. Проблема в том, что код не будет работать, потому что enum не является типа как int есть. Я пытался сделать что-то с дженериками:

public static class EnumExt
{
    public static T AddFlag<T>(this T e, T flag) 
        where T : Enum      // Can't constrain to Enum
    {
        return e = e | flag;
    }
}

и это:

public static T AddFlag<T>(this T e, T flag) 
    where T : struct
{
    if (!(typeof(T).IsEnum)) return default; 

    return e |= flag;      // Operator '|' cannot be applied to T
}

У которого есть две проблемы. Поскольку это struct, это означает, что этот метод будет отображаться для значений int. Я использую struct только потому, что это самое близкое ограничение к Enum. Я выхожу из метода, если это не Enum, но это все еще не дает компилятору понять, что e - это enum, даже если это всегда должно быть в этой точке.

Также пытались использовать where T : int и использовать приведение, но int является недопустимым ограничением.

Есть ли в любом случае это можно сделать?

РЕДАКТИРОВАТЬ : Я попробовал два ответа, которые были предложены как решение проблемы, но они этого не делают. Тот, у которого IEnumConstraint не работает, потому что говорит, что мой enum не наследуется от него, и ни один из ответов не позволяет мне на самом деле return e |= flag;

// Doesn't work because C# won't allow bitwise operators on generic types 
// Because the constraint is still vague enough for non-enum values to slip through
public static T AddFlag<T>(this T e, T flag)
    where T : struct, IConvertible

// Doesn't work because enums don't inherit from IEnumConstraint
// Same as above
public static T AddFlag<T>(this T e, T flag)
    where T : struct, IEnumConstraint

Я предполагаю, что, даже если они ограничены только значениями Enum, некоторые другие классы все еще могут наследовать от IEnumConstraint и IConvertible, поэтому побитовые операторы не будут работать, поскольку гарантия того, что операция будет доступна для T.

Кажется, единственное реальное решение - в C # 7.3, где они позволяют использовать System.Enum в качестве ограничения.

1 Ответ

0 голосов
/ 16 мая 2018

Был в состоянии понять это.Я должен привести от T к object, затем к int, использовать побитовые операторы для значений int, а затем повернуть его вспять, чтобы получить результат обратно.

@ mjwills отметил, что C # 7.3 не решит проблему приведения.Все, что это исправит, это ограничение, и я смогу удалить исключение броска.

public static T AddFlag<T>(this ref T e, T flag)
    where T : struct, IConvertible
{
    if (!(typeof(T).IsEnum)) throw new ArgumentException("Value must be an enum");

    int added = (int)(object)e | (int)(object)flag;

    e = (T)(object)added;

    return e;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...