2010-09-25 2 views
3

Рассмотрим следующий кодпараметр Метод с сильно типизированных типа Enum

enum HorizontalAlignment { Left, Middle, Right }; 
enum VerticleAlignment { Top, Middle, Bottom }; 

function OutputEnumValues (Type enumType) 
{ 
    foreach (string name in Enum.GetNames(typeof(enumType))) 
    { 
     Console.WriteLine(name); 
    } 
} 

который можно назвать как

OutputEnumValues (typeof(HorizontalAlignment)); 
OutputEnumValues (typeof(VerticleAlignment)); 

Но я мог бы ненароком назвать, например

OutputEnumValues (typeof(int)); 

И это будет компилироваться, но сбой во время выполнения в Enum.GetNames()

Любой способ написания сигнатуры метода, чтобы поймать эту проблему во время компиляции - т. Е. Только принимать типы перечисления в OutputEnumValues?

ответ

4

Каждый тип перечисления представляет собой целое число (которое может быть 8-, 16-, 32- или 64-битным и подписанным или без знака). Вы можете отличить целое число 0 от любого типа перечисления, и оно станет значением, которое статически вводится в перечисление.

Кроме того, вы можете иметь параметр типа Enum, чтобы обеспечить передачу только значений перечисления, не зная фактического типа перечисления.

Таким образом, мое решение выглядит следующим образом:

public static void OutputEnumValues(Enum example) 
{ 
    foreach (string name in Enum.GetNames(example.GetType())) 
    { 
     Console.WriteLine(name); 
    } 
} 

, а затем:

OutputEnumValues((HorizontalAlignment) 0); 
OutputEnumValues((VerticalAlignment) 0); 

Это работает для всех типов перечислений независимо от их базового целого типа.

+0

Переходя в 0, набрав enum, немного «грязно» и не будет очевидным для пользователей метода, но может быть наименее худшим вариантом, поэтому +1 от меня. – Ryan

1

Я не думаю, что это возможно в C#.

Вместо этого вы можете использовать метод расширения в Enum, но для этого вам потребуется вызвать его на экземпляр, а не на сам тип, который может быть нежелательным.

Альтернативное решение с использованием дженериков, который получает вас часть пути является сдерживающим фактором для структур:

public static void OutputValues<T>() where T : struct 
{ 
    if (!typeof(T).IsEnum) 
     throw new NotSupportedException("Argument must be an enum."); 

    // code here... 
} 

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

1

Что вы действительно хотите здесь, это универсальный метод, который может сдерживать тип Enum. Однако это невозможно в C#.

Джон Скит есть ответ на эту проблему в этой теме: Anyone know a good workaround for the lack of an enum generic constraint?

Для вашего метода, что вы действительно хотите

public void OutputEnumValues<T>() where T : HorizontalAlignment 
{ 
    foreach (string name in Enum.GetNames(typeof(T))) 
    { 
     Console.WriteLine(name); 
    } 
} 

Но это ограничение не будет работать, если вы не используете предложение Джона ,

0

Я не вижу «проблему», как вы ее заявляете.

Вы определяете свой метод для получения объекта типа. Клиентам любой тип кажется достаточным. Тем не менее, вы тогда считаете, что аргумент фактически является перечислением. Ошибка в вашем методе. В любом случае, сам метод изобретателен, поэтому невозможно понять, какую проблему вы пытаетесь решить с помощью такого кода.

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

+1

Я думаю, что его вопрос ясен. Да, пример надуман, но намерение ясно. Ему все равно, какой тип Enum get прошел, но он хочет убедиться, что это НЕКОТОРЫЙ тип Enum (так что Enum.GetNames не подведет). Это идеальный случай для универсального метода с ограничением Enum (однако C# в настоящее время не поддерживает это) –

+0

Итак ... это идеальный случай для неподдерживаемой языковой функции? Полезно. Я хочу сказать, что если метод явно документирован, чтобы использовать тип перечисления, чем клиенты этого кода получают то, что они заслуживают, если они передают мусор. Говорить о функциях, которые не существуют, это пустая трата времени. –

+0

Я предполагаю, что я просто привык к другому стилю программирования. В моем мире (системные/встроенные) функции документированы, чтобы ожидать определенные аргументы. Если вы передадите плохие данные, вы получите то, что заслуживаете. Если вы можете ограничить метод, чтобы использовать только тип перечисления, отлично. Поскольку вы не можете, я не вижу смысла даже в обсуждении этого. Я не вижу проблемы с вызовом исключения во время выполнения. –

Смежные вопросы