2013-09-01 2 views
1

У меня есть частный член типа List<T>, где T - это объекты с богатым доменом. Домен в моем приложении содержит много методов, которые ожидают T.Публикация списка <объекты домена> через IList <interface>

Я хочу представить публичное имущество типа IList<IT> где T : IT. IT имеет небольшой размер, который реализуется DTO.

Поскольку я не могу отличить List<T> до IList<IT> Я прибегаю к использованию List<T>.ConvertAll в объявлении собственности.

Это лучший способ сделать это? Быстрее, элегантнее?

Редактировать, чтобы обеспечить дополнительные детали

T являются базовым классом, для которого ряд производных классов существует, и каждый из этих производных классов происходит во многих различных вкусах (конфигураций загружены во время выполнения). Пользователь на уровне презентации может добавлять/изменять/удалять любые экземпляры этих производных классов любой конфигурации. Экземпляры также могут быть привязаны друг к другу друг с другом, но существуют некоторые сложные правила, которые определяют, какие ссылки разрешены; некоторые из которых известны во время компиляции, некоторые из которых известны только во время выполнения (на основе конфигураций). Некоторые экземпляры могут быть двусвязными, некоторые сшитые, некоторые только одно в любом направлении, некоторые - только в одном направлении, а некоторые - нет.

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

В классе T существует множество других членов и методов, которые будут функционировать на фабриках и классах услуг. Некоторые ведут себя очень похоже на пример выше. Ни одна из них не должна открываться вне сборки.

+2

Нужно ли его изменять? – SLaks

+0

Стефан, а также @SLaks намекнул. Это зависит от того, что вы ожидаете от клиентов на самом деле с этим списком. Разрешено ли им добавлять к нему или удалять из него? Разделяется ли она между несколькими клиентами? Представляет ли он концепцию домена сама по себе (например, команда, запрос, ...)? и т. д. Это зависит от вашего варианта использования. – Alex

+1

Если ваш список * * readonly, вы можете использовать IReadOnlyList . – zmbq

ответ

0

Предположим, что вы могли бы сделать что-то вроде этого:

// NOT REAL CODE 
public interface IMyInterface { } 
public class MyRealClass : IMyInterface { } 

... 

public class Domain 
{ 
    private List<MyRealClass> myList; 

    public IList<IMyInterface> Interfaces { get { return (IList<IMyInterface>)this.myList; } } 
} 

Что остановить пользователя этого Domain класса делать это?

public class MyFakeClass : IMyInterface { } 

... 

domain.Interfaces.Add(new MyFakeClass()); 

Очевидно, что это будет проблематично, поскольку myList в действительности List<MyRealClass>, но компилятор не может гарантировать, что только экземпляры MyRealClass добавляются в список (она требует проверки во время выполнения). Другими словами, такое поведение не безопасно для типов, поэтому компилятор не допустит этого.

Вы можете выставить IList/ICollection из IMyInterface — который типобезопасным, но не гарантирует, что только ваша MyRealClass добавляется в список.

public class Domain 
{ 
    private List<IMyInterface> myList; 

    public IList<IMyInterface> Interfaces { get { return this.myList; } } 
} 

В качестве альтернативы, можно выставить в IEnumerable из IMyInterface (или IReadOnlyList, так как предполагает zmbq) —, так как параметр типа ковариантен (см Covariance and Contravariance in Generics). Хотя это не позволит вам добавлять новые элементы в коллекцию.

public class Domain 
{ 
    private List<MyRealClass> myList; 

    public IEnumerable<IMyInterface> Interfaces { get { return this.myList; } } 
} 

Другим решением было бы реализовать свой собственный класс коллекции, который фактически реализует из IList<IMyInterface>, но генерирует исключение, если пользователь пытается вставить что-либо иное, чем MyRealClass. Это не особенно элегантное решение, и, с практической точки зрения, оно не отличается от простого отображения IList<MyRealClass>.

+0

Внутренняя фабрика в домене отвечает за создание 'MyRealClass', поэтому я не боюсь получать« MyFakeClass ». Реальная задача заключается в том, чтобы скрыть внутренний IP-адрес и минимизировать размер DTO. Поскольку у MyRealClass есть множество методов, я хочу избежать того, чтобы каждый DTO создавал для них заглушку, просто потому, что для этого нужен интерфейс. –

+0

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

-1

Если я правильно понимаю вас, вы должны использовать метод выбора Linqs для преобразования своего списка в IList. Итак, вы делаете что-то вроде:

List<T> myList = ... 
IList<IT> b = myList.Select(a=> a as IT).ToList(); 
+0

То же самое с 'myList.ConvertAll (a => a as IT)'. 'Select' - это ленивая версия' ConvertAll'. – Teejay