Примените Enum, чтобы вернуть Generi c C# 7.3 - PullRequest
0 голосов
/ 01 мая 2020

Более чем это концептуально неправильно понято, но я хочу знать, почему.

У меня есть метод stati c, который может вернуть одно значение c generi, и он также получает строку .

public static T GetWordType<T>(string word) where T : System.Enum
{
    if (typeof(T) == typeof(ActionType))
    {
        foreach (Word<ActionType> action in actionsList)
        {
            if (action.synonims.Contains(word))
                return action.type;
        }
        return ActionType.None;
    }
    return WordType.None;
}

При всех возвратах возникает ошибка приведения с заголовком «Вы не можете неявно преобразовать Action.ActionType в T».

Почему?

Мой класс действий - объявлено наследование от абстрактного класса Word, определенного следующим образом:

public abstract class Word<T> where T : System.Enum
{
    public List<string> synonims;
    public T type;
}

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

EDIT : В качестве петиции от Павла Аниховского мой enum-тип ActionType объявлен внутри класса Action следующим образом:

class Action : Word<ActionType>
{
    public enum ActionType
    {
        Open, Close, Shutdown, Stop, Send, Save, Load, Move, Add, Cancel, None
    }
}

, а мой перечисление WordType тестовое перечисление, которое может быть любым перечислением в данный момент, просто устанавливает его для проверки возврата различных перечислений. Что-то вроде:

public enum WordType
{
    None, Test
}

1 Ответ

1 голос
/ 01 мая 2020

Взгляните на это, когда я достану то, что находится внутри вашего if:

public static T GetWordType<T>(string word) where T : System.Enum
{
    if (typeof(T) == typeof(ActionType))
    { … }

    return ActionType.Cancel;
}

Как видите, вы проверяете, является ли T ActionType. Если это , а не , тогда вы возвращаете ActionType.Cancel, что, очевидно, является ActionType. Но ваш метод должен возвращать T, который вы только что доказали , а не как ActionType.

Так что вместо T вы на самом деле хотите, чтобы ваш метод возвратил ActionType во всех случаях, потому что это именно то, что вы делаете:

public static ActionType GetWordType<T>(string word) where T : System.Enum
{
    if (typeof(T) == typeof(ActionType))
    {
        foreach (Word<ActionType> action in actionsList)
        {
            if (action.synonims.Contains(word))
                return action.type;
        }
        return ActionType.None;
    }
    return ActionType.Cancel;
}

И в этот момент можно утверждать, что вам даже не нужен универсальный c метод, потому что вы на самом деле мало что делаете с этот параметризованный тип T, кроме проверки его точного типа.

Обычно плохая идея иметь дело с фактическими возможными типами для T внутри методов generi c. Это делает ваш метод, который должен быть обобщенным c для всех совместимых типов, хрупким, поскольку вы ищете точные типы, но на самом деле имеете дело с бесконечным числом типов T, которые вы не можете планировать .


С тех пор вы изменили свой вопрос, и он возвращает ActionType.None внутри if и WordType.None вне условия. Вы все еще возвращаете конкретные типы, поэтому ваш метод не может вернуть T. И это также не будет работать, потому что ActionType и WordType являются отдельными типами, и перечисления не допускают наследования, которое могло бы сделать эту работу для других типов возврата.

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


Если вы действительно имели в виду возвращаемое значение * Если 1046 * будет значением типа enum T, то, что вы могли бы сделать, всегда возвращать значение по умолчанию для перечисления. Таким образом, ваш метод может быть обобщенным c с пользовательской обработкой для ActionType:

public static T GetWordType<T>(string word) where T : System.Enum
{
    if (typeof(T) == typeof(ActionType))
    {
        // you know `T` is `ActionType`, so you can cast to `T`:
        return (T)(object)ActionType.None;
    }

    // since you don’t know `T`, you cannot refer to actual values on
    // the imaginary enum `T`; you can however use the default value
    // (which will be the value 0, by default the first enum value)
    return default(T);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...