C # Globals / Constants, привязываемые к DDL, но с "хорошими" именами - PullRequest
1 голос
/ 20 июля 2011

По обычным причинам мне нужно использовать некоторые константы в моем приложении.

Подходы, которые я рассмотрел:

1) Объявить Enum:

public enum myOptions
{
  MyOption1 = 72,
  MyOption2 = 31,
  MyOption3 = 44
}

Хотя это хорошо для программирования, и я могу связать enum напрямую с DDL, но «имена» Enum ужасны, когда пользователь их видит - пользователь увидит «MyOption1», а я хочу, чтобы они увидели » Мой вариант № 1 ".

2) Использовать список:

public static List<KeyValuePair<int, string>> myOptions = new List<KeyValuePair<int, string>>
{
 new KeyValuePair<int, string>(77, "My Option #1"),
 new KeyValuePair<int, string>(31, "My Option #2"),
 new KeyValuePair<int, string>(44, "My Option #3")
}

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

if (selectedOption=????) //I'd have to hardcode the Key or Value I want to test for.

3) Я мог бы создать хорошую сборку Global / Constants:

static myOptions
{
 public static KeyValuePair<int, string> MyOption1 = new new KeyValuePair<int, string>(77, "My Option #1");
 public static KeyValuePair<int, string> MyOption2 = new new KeyValuePair<int, string>(31, "My Option #2");
 public static KeyValuePair<int, string> MyOption3 = new new KeyValuePair<int, string>(44, "My Option #3");
}

То, что дает мне хорошие отображаемые имена, приятно кодировать, но, насколько я могу судить, у меня нет способа легко связать это с DDL (я должен был бы вручную кодировать это).

Есть ли у кого-нибудь элегантный способ создания констант, которые легко связаны с DDL, где у меня может быть хорошее отображаемое имя?

Прямо сейчас единственное, о чем я могу думать, - это создание ОБА Enum и Списка, что кажется раздражающим.

Ответы [ 3 ]

2 голосов
/ 20 июля 2011

Я всегда склоняюсь к декорированным значениям перечисления:

public enum myOptions
{
    [Description("My Option #1")]
    MyOption1 = 72,
    [Description("My Option #2")]
    MyOption2 = 31,
    [Description("My Option #3")]
    MyOption3 = 44
}

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

public enum myOptions
{
    [Custom("MyOption1Key")]
    MyOption1 = 72,
    [Custom("MyOption2Key")]
    MyOption2 = 31,
    [Custom("MyOption3Key")]
    MyOption3 = 44
}

Обновление для общего извлечения атрибутов из перечисления

public static T GetAttribute<T>(this Enum e) where T : Attribute
{
    FieldInfo fieldInfo = e.GetType().GetField(e.ToString());
    T[] attribs = fieldInfo.GetCustomAttributes(typeof(T), false) as T[];
    return attribs.Length > 0 ? attribs[0] : null;
}
1 голос
/ 03 февраля 2012

Другое предложение?

public static List<KeyValuePair<int, string>> GetKeyValuePairs<T>()
    {
        Type enumType = typeof(T);

        List<KeyValuePair<int, string>> ret = new List<KeyValuePair<int, string>>();
        foreach (Enum val in Enum.GetValues(enumType))
        {
            ret.Add(
                new KeyValuePair<int, string>(Convert.ToInt32(val),
                val.GetAttribute<DescriptionAttribute>().Description)
                );
        } return ret;
    }

Тогда вы можете связываться, не создавая экземпляр перечисления. Это тип enum, о котором вы хотите получить информацию, а не конкретный экземпляр)

ddlPes.DataSource = EnumHelper.GetKeyValuePairs<PesId>();
ddlPes.DataValueField = "key";
ddlPes.DataTextField = "value";
ddlPes.DataBind();
1 голос
/ 21 июля 2011

Исходя из ответа, предоставленного @hunter, я решил опубликовать свою полную реализацию, так как мне потребовалось некоторое время, чтобы понять ее правильно (все еще учусь здесь ...)

// This is the class I used to hold the extensions.
public static class EnumFunctions
{
    // Custom GetAttribute Extension - used to pull an attribute out of the enumerations.
    // This code is as per Hunter's answer, except I added the null check.
    public static T GetAttribute<T>(this Enum e) where T : Attribute
    {
        FieldInfo fieldInfo = e.GetType().GetField(e.ToString());

        // If the enumeration is set to an illegal value (for example 0,
        // when you don't have a 0 in your enum) then the field comes back null.
        // test and avoid the exception.
        if (fieldInfo != null)
        {
            T[] attribs = fieldInfo.GetCustomAttributes(typeof(T), false) as T[];
            return attribs.Length > 0 ? attribs[0] : null;
        }
        else
        {
            return null;
        }
    }

    // Custom GetKeyValuePairs - returns a List of <int,string> key value pairs with
    // each Enum value along with it's Description attribute.
    // This will only work with a decorated Enum. I've not included or tested what
    // happens if your enum doesn't have Description attributes.
    public static List<KeyValuePair<int, string>> GetKeyValuePairs(this Enum e)
    {
        List<KeyValuePair<int, string>> ret = new List<KeyValuePair<int, string>>();

        foreach (Enum val in Enum.GetValues(e.GetType()))
        {
            ret.Add(new KeyValuePair<int, string>(Convert.ToInt32(val), val.GetAttribute<DescriptionAttribute>().Description));
        }
        return ret;
    }

}

В другом месте, чтобы сделатьпривязку к DDL вы можете просто сделать так:

{
    // We need an instance of the enum to call our extension method.
    myOptions o = myOptions.MyOption1;

    // Clear the combobox
    comboBox1.DataSource = null;
    comboBox1.Items.Clear();

    // Bind the combobox
    comboBox1.DataSource = new BindingSource(o.GetKeyValuePairs(), null);
    comboBox1.DisplayMember = "Value";
    comboBox1.ValueMember = "Key";      
}

Наконец, чтобы извлечь выбранное значение, вы можете сделать это:

{
    // Get the selected item in the combobox
    KeyValuePair<int, string> selectedPair = (KeyValuePair<int, string>)comboBox1.SelectedItem;

    //I'm just sticking the values into text labels to demonstrate.
    lblSelectedKey.Text = selectedPair.Key.ToString();
    lblSelectedValue.Text = selectedPair.Value.ToString();
}

.. и я не остановилсятам.Я расширил сам элемент управления ComboBox, так что связывание его теперь очень удобно.

    // Extends the Combobox control so that it can be automatically bound to an Enum
    // that has been decorated with Description attributes.
    // Sets the current value of the combobox to the value of the enum instance passed in.
    public static void BindToDecoratedEnum(this System.Windows.Forms.ComboBox cb, Enum e)
    {
        // Clear the combobox
        cb.DataSource = null;
        cb.Items.Clear();

        // Bind the combobox
        cb.DataSource = new System.Windows.Forms.BindingSource(e.GetKeyValuePairs(), null);
        cb.DisplayMember = "Value";
        cb.ValueMember = "Key";

        cb.Text = e.GetAttribute<DescriptionAttribute>().Description;
    }

Так что теперь, когда я хочу заполнить DDL, я просто:

        myDDL.BindToDecoratedEnum(myEnumInstanceWithValue);

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

Комментарии и критика моей реализации приветствуются (на самом деле, я был бы благодарен - как я уже сказал, я пытаюсьузнать ...)

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