C# Indexer Свойство Вопрос
У меня есть такой класс:
public class SomeClass
{
private const string sessionKey = "__Privileges";
public Dictionary<int, Privilege> Privileges
{
get
{
if (Session[sessionKey] == null)
{
Session[sessionKey] = new Dictionary<int, Privilege>();
}
return (Dictionary<int, Privilege>)Session[sessionKey];
}
}
}
Теперь, если я сделаю это...
var someClass = new SomeClass();
var p = someClass.Privileges[13];
... и нет ключа 13, я получу ошибку, как это:
The given key was not present in the dictionary.
Я хотел бы иметь свойство, к которому можно получить доступ так же, как и выше, но вернет объект по умолчанию в случае отсутствия ключа.
Я попытался создать свойство индексатора, как это...
public Privilege Privileges[int key]
{
get
{
try { return _privileges[key]; }
catch { return new Privilege(); }
}
}
... но похоже, что это не языковая особенность C# 2008.
Как я могу получить доступ к свойству таким же образом, но получить объект по умолчанию, если ключ отсутствует?
4 ответа
Вы должны будете определить свой собственный класс на основе IDictionary с помощью индексатора, который имеет желаемое поведение, и вернуть его экземпляр, а не стандартный словарь класса, в свой метод получения свойств.
C# не поддерживает именованные индексаторы, как вы обнаружили.
Рассматривали ли вы использовать обычный метод вместо свойства индексатора? Не каждая проблема программирования требует использования причудливого синтаксиса для решения. Да, вы можете создать свою собственную реализацию IDictionary с агрегированным словарем и изменить поведение доступа к свойству - но действительно ли это необходимо для чего-то, что просто выбирает значение или возвращает значение по умолчанию?
Я бы добавил такой метод в ваш класс:
protected Privilege GetPrivilege(int key)
{
try { return _privileges[key]; }
catch { return new Privilege(); }
}
или еще лучше, избегайте обработки исключений как механизма управления потоком:
protected Privilege GetPrivilge( int key )
{
Privilege priv;
if( _privileges.TryGetValue( key, out priv ) )
return priv;
else
return new Privilege();
}
Индексаторы в C# могут использоваться только с this
ключевое слово.
Я подозреваю, что вы хотите что-то вроде этого:
public Privilege this[int key]
{
get
{
try { return _privileges[key]; }
catch { return default(Privelege); }
}
}
который вы можете определить либо непосредственно в SomeClass
так что вы можете получить доступ к элементу privelege, как:
SomeClass foo;
var bar = foo[100];
или определить этот индексатор в пользовательском классе, который реализует из IDictionary<TKey, TValue>
(и содержит Dictionary<TKey, TValue
внутренне для фактического хранения данных). Вы могли бы тогда использовать это как:
SomeClass foo;
var bar = foo.Priveleges[100];
Какой синтаксис вы предлагаете, и какой может быть наиболее подходящим, хотя это требует немного больше усилий.
Вы должны использовать этот синтаксис для получения значения:
public Privilege this[int key]
{
get
{
var value = (Privilege)null;
if(!_privileges.TryGetValue(key, out value))
value = new Privilege();
return value;
}
}
Мне очень нужно такое использование IDictionary, поэтому я сделал несколько методов расширения:
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key)
{
TValue v = default(TValue);
d.TryGetValue(key, out v);
return v;
}
public static TValue Get<TKey, TValue>(this IDictionary<TKey, TValue> d, TKey key, Func<TValue> value)
{
TValue v = d.Get(key);
if (v == null)
{
v = value();
d.Add(key, v);
}
return v;
}
Теперь вы можете написать:
public Privilege this[int key]
{
get
{
return _privileges.Get(key, () => new Privilege());
}
}