Как создать иерархические классы / перечисления для использования в качестве ключа в коллекции в .NET C # - PullRequest
1 голос
/ 23 марта 2011

У меня есть набор материалов в общем Dictionary<string, object>().

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

Поэтому вместо того, чтобы делать это: object value = myDictionary["App1.Account1.SomeSetting"]; Я хочу иметь возможность сделать это:

object value = myDictionary[App1.Account1.SomeSetting]; (обратите внимание на отсутствие кавычек вокруг ключа.

Это означает, что словарь станет Dictionary<{something}, object>().

Каков наилучший способ определить это {что-то}? Он был бы строго напечатан и работал бы так:

App1 - может быть любымколичество приложений В приложении App1 может быть много учетных записей (App1.Account1). В учетных записях может быть много настроек (App1.Account1.Setting1)

Структура данных {нечто} будет жестко закодирована со всеми возможными уровнями / настройками, ноЯ не могу придумать, как это можно организовать, чтобы по-прежнему работать в качестве ключа.

РЕДАКТИРОВАТЬ: См. Мой ответ ниже для решения. Надеюсь, это поможет кому-то еще.

Ответы [ 3 ]

2 голосов
/ 23 марта 2011

Мне кажется, я понимаю, что вы хотите: вы хотите, чтобы ваш «плоский» словарь ключей и значений был сделан доступным, указав проверенный компилятором набор идентификаторов, который оценивает строку, являющуюся ключом словаря.

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

Вместо этого у вас может быть относительно простая структура:

public class App
{
   public Account[] Accounts {}
}

public class Account
{
   public decimal ApprovedAmount {get;set;}
   public int ContractLength {get;set;}
}

... а затем либо определите константу App1, App2 и т. Д., Либо установите для этих классов сериализуемый формат XML или сопоставленный с ORM, чтобы они могли быть сохранены в некоторой относительно программно-независимой, человеко-потребляемое состояние.

0 голосов
/ 24 марта 2011

В конечном итоге это было решение, которое я реализовал, с некоторыми обобщениями и некоторой предопределенной иерархией классов для замены дерева «настроек».

Использование:

    Settings secSettings = new Settings();

    secSettings.Add(new SettingNames.App1.Screen1.MaxBillAmountToConsolidate(), 50m);

    secSettings.Add(new SettingNames.App2.SingleSetting(), new DateTime(2010, 11, 25));

    secSettings.Add(new SettingNames.App1.Screen2.CanEditField2(), false);
    secSettings.Add(new SettingNames.App1.Screen2.CanEditField3(), true);

    int amount;
    if (secSettings.TryGetValue(new SettingNames.App1.Screen1.MaxBillAmountToConsolidate(), out amount))
    {
        Print(amount);
    }

    DateTime expiredDate;
    if (secSettings.TryGetValue(new SettingNames.App2.SingleSetting(), out expiredDate))
    {
        Print(expiredDate);
    }

    bool permission;
    if (secSettings.TryGetValue(new SettingNames.App1.Screen2.CanEditField2(), out permission))
    {
        Print(permission);
    }

    if (secSettings.TryGetValue(new SettingNames.App1.Screen2.CanEditField3(), out permission))
    {
        Print(permission);
    }

Настройки классов (каждый класс, естественно, в своем собственном файле, но все в одном и том же пространстве имен):

namespace Security
{

/// <summary>
/// Base class from which all Security Setting instances must inherit
/// </summary>
public abstract class SettingNameBase
{
    /// <summary>
    /// Returns fully qualified type name of the instance of this class as a string
    /// </summary>
    public override string ToString()
    {
        return this.GetType().FullName;
    }

}

[DataContract]
public class Settings
{
    [DataMember]
    private Dictionary<String, Object> settings = new Dictionary<String, Object>();

    public void Add<T>(SettingNameBase name, T value)
    {
        if (!settings.ContainsKey(name.ToString()))
        {
            settings.Add(name.ToString(), value);
        }
        else
        {
            throw new ArgumentException(string.Format("A setting with the key '{0}' already exists.", name.ToString().Replace("+", ".")));
        }
    }

    public bool TryGetValue<T>(SettingNameBase name, out T value)
    {
        bool dictContainsKey = false;

        if (dictContainsKey = settings.ContainsKey(name.ToString()))
        {
            try
            {
                value = (T)Convert.ChangeType(settings[name.ToString()], typeof(T));
            }
            catch (InvalidCastException ex)
            {
                string errMsg = string.Format("Invalid cast of value '{0}' to type of {1} in Setting.Value<T>() method.",
                    settings[name.ToString()], typeof(T).FullName);

                throw new InvalidCastException(errMsg, ex);
            }
        }
        else
        {
            value = default(T);
        }

        return dictContainsKey;
    }

}

    public class SettingNames
    {
        /// <summary>
        /// Setting for a user
        /// </summary>
        public class User
        {
            public class Name : SettingNameBase { }
            public class ID : SettingNameBase { }
            public class Password : SettingNameBase { }
        }

        /// <summary>
        /// Setting for App1
        /// </summary>
        public class App1
        {
            public class Screen1
            {
                public class CanEditField1 : SettingNameBase { }
                public class MaxBillAmountToConsolidate : SettingNameBase { }
            }
            public class Screen2
            {
                public class CanEditField2 : SettingNameBase { }
                public class CanEditField3 : SettingNameBase { }
            }
        }

        /// <summary>
        /// Setting for App2
        /// </summary>
        public class App2
        {
            public class SingleSetting : SettingNameBase { }
        }
    }
}
0 голосов
/ 24 марта 2011

Деревья естественным образом подходят для кодирования иерархической информации. Используйте дерево.

...