Я ищу, чтобы узнать, есть ли способ легко выставить мои контейнеры из классов C#, не раскрывая ненужных деталей реализации. Я изучаю C#, но у меня есть опыт работы на других языках OO, поэтому я знаю, что там, где это возможно, лучше показывать базовые классы/интерфейсы, а не конкретные типы. То, что я делаю, - это хранение коллекций ключа (коллекции объекта) в моем классе. Я нахожу, что я могу легко разоблачить это как IDictionary (ключ, коллекция объекта), но мне хотелось бы IDictionary (key, IEnumerable (object)). Надеюсь, простой пример сделает его более ясным.Удобный способ опубликовать значение словаря в качестве базовых типов
class AddressBook
{
public IDictionary<string, List<string>> Name2Addresses // ok, but I want IDictionary<string, IEnumerable<string>>
{
get { return name2Addresses; }
}
public IEnumerable<string> GetAddresses(string name)// ok, but I really just want the convenience of exposing container as a "one-liner"
{
return name2Addresses[name];
}
public AddressBook()
{
name2Addresses = new Dictionary<string,List<string>>();
List<string> addresses = new List<string>(); // I'd prefer IList<string> addresses = ...
name2Addresses.Add("Anne Best", addresses);
addresses.Add("Home address");
addresses.Add("Work address");
}
Dictionary<string, List<string>> name2Addresses;
}
Я знаю, что разоблачение контейнера, полученные в качестве контейнера базы является сложной проблемой в OO, потому что, например, можно добавить другую, полученные с помощью контейнера базового класса. Но, надеюсь, потому что я хочу показать контейнер как доступный только для чтения через IEnumerable, может быть простой способ сделать это. Это код, который я хочу.
public IDictionary<string, IEnumerable<string>> Name2Addresses
{
get { return name2Addresses; }
}
Я попытался добавить слепок как компилятор жаловался, не имея один
public IDictionary<string, IEnumerable<string>> Name2Addresses
{
get { return (IDictionary<string, IEnumerable<string>>) name2Addresses; }
}
, но потом я получил исключение:
Дополнительная информация: Не удается привести объект типа 'System.Collections.Generic.Dictionary
2[System.String,System.Collections.Generic.IList
1 [System.String]]' для ввода 'System.Collections.Generic.IDictionary2[System.String,System.Collections.Generic.IEnumerable
1 [System.String]] '.
Любые идеи? Я надеялся, что может быть легкий/элегантный способ сделать это, так как в целом было радостью перейти от языка OO более низкого уровня к C#, где гораздо быстрее и проще использовать то, что я хочу на практике. Это не шоу-стоппер каким-либо образом, поскольку я могу просто раскрыть List, а не IEnum и доверять себе, чтобы не злоупотреблять списком, но я хотел бы сделать все правильно, особенно, поскольку, надеюсь, у меня будут другие люди, которые однажды используют мой код ,
PS Я помню, где-то читал, что C# недавно улучшил поддержку такого рода вещей. Я на VS2010, если это имеет значение.
Редактировать
Я сделал некоторые поиски, прежде чем спрашивать, но после еще некоторых поисков, я нашел, что это было предложено ранее, в несколько ином контексте, Why can't Dictionary<T1, List<T2>> be cast to Dictionary<T1, IEnumerable<T2>>?. Так что мой вопрос, возможно, сводится к есть ли способ, имеющие только для чтения IDictionary (см также Is there a read-only generic dictionary available in .NET?)
других Редактировать
Как предложил Алекс G/code4life, это будет работать: без прокатки собственных чтений - Только класс словаря я могу создать новый словарь. Например.
public IDictionary<string, IEnumerable<string>> Name2AddressesNewDictionary
{
get
{
return name2Addresses.ToDictionary(na=>na.Key, na=>na.Value.AsEnumerable());
}
}
Это влечет снижение производительности каждый раз, когда доступ + пробел штраф создание новых пар ключ-значение (и сам Dict). Кроме того, дополнительное время для разработчиков. Не кажется лучше, чем разоблачение Перечня, в общем, если я использую свойство (особенно, поскольку работа продолжается под обложками). Но было бы хорошо как метод/в других обстоятельствах.
Третий Edit
Как предложил Jens Kloster, изменить определение контейнера использовать IEnumerable в качестве значения
Dictionary<string, IEnumerable<string>> name2Addresses;
и затем отливали, когда вам нужно в реализации.
((IList<string>)name2Addresses["Anne Best"]).Add("Alternative address");
предложил Ваше решение является слишком трудоемким. Я бы предложил либо определить «Словарь <строка, IEnumerable>», либо использовать 'name2Addresses.ToDictionary (k - => key, v => v.Value.AsEnumerable()) вместо этого - это как исправления 1-лайнера к вашей проблеме. –
code4life
Да, я в целом согласен с тем, что вы пишете, и меня поправляет мой вопрос. У меня просто проблемы с редактированием достаточно быстро, чтобы идти в ногу со всеми полезными предложениями! (первый раз я задал вопрос о SO, v доволен ответом) – TooTone