У меня есть класс вроде этого:
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];
}
}
}
Теперь, если Ido это...
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(); }
}
}
... но похоже, что это не язык языка С# 2008.
Как я могу получить доступ к свойству таким же образом, но получить объект по умолчанию, если ключ отсутствует?
Вам нужно будет определить свой собственный класс на основе IDictionary с индексом, который имеет желаемое поведение, и вернуть экземпляр этого, а не класса словаря запасов в ваш получатель.
С# не поддерживает названные индексы, как вы обнаружили.
Рассматривали ли вы использование обычного метода вместо свойства индексатора? Не каждая проблема программирования требует использования мозаичного синтаксиса для решения. Да, вы могли бы создать свою собственную реализацию 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();
}
Индексаторы на С# могут использоваться только с ключевым словом 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());
}
}
this
.