2015-02-03 5 views
4

Я пытаюсь создать псевдоним для типа списка списка объектов. В частности, я хочу, чтобы сократить все типизации, я должен сделать для этого типа:Создание класса или интерфейса для сложного общего типа

IReadOnlyList<IReadOnlyList<MyObject>> 

Моя попытка демонстрируется здесь:

using System.Collections.Generic; 

namespace MyApp 
{ 
    class Program 
    { 
     public class MyObject 
     { 
      public static IMyCollection GetCollection() 
      { 
       var a = new List<MyObject>(); 
       a.Add(new MyObject()); 

       var b = new List<IReadOnlyList<MyObject>>(); 
       b.Add(a.AsReadOnly()); 

       return b.AsReadOnly(); 
      } 
     } 

     public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>> 
     { 
     } 

     static void Main(string[] args) 
     { 
      var collection = MyObject.GetCollection(); 
     } 
    } 
} 

К сожалению, это не будет компилироваться. Там ошибка:

Cannot implicitly convert type 
'System.Collections.ObjectModel.ReadOnlyCollection<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>' 
to 'MyApp.Program.IMyCollection'. 
An explicit conversion exists (are you missing a cast?) 

ОК, поэтому я рядом. Возможно, явное литье? Поэтому я меняю заявление возвращения в GetCollection к

return (IMyCollection)b.AsReadOnly(); 

Это компилирует, хотя и с предупреждением ReSharper: Подозрительный бросок: нет тип в растворе, который наследуется от обоих «System.Collections.ObjectModel.ReadOnlyCollection>» и «MyApp.Program.IMyCollection»

и во время выполнения, я получаю недопустимое исключение произнесения: Не удается привести объект типа 'System.Collections.ObjectModel.ReadOnlyCollection 1[System.Collections.Generic.IReadOnlyList 1 [MyApp.Program + MyObject]], чтобы ввести 'IMyCollection.

ОК, я могу принять все это. Я последний человек, который спрашивает о таких вещах, как ковариация и контравариантность, и тому подобное. Но, конечно же, есть способ определить и создать объект с коротким именем, чтобы стоять для действительно длинного именованного типа данных.

Как создать тип с действительно длинным именем и применить к типу с действительно коротким именем?

ОБНОВЛЕНИЕ: Сотрудник предложил использовать заявление using.

using IMyCollection= System.Collections.Generic.IReadOnlyList<System.Collections.Generic.IReadOnlyList<MyApp.Program.MyObject>>; 

Хотя это будет работать, это становится необходимым, чтобы сделать это в каждом файле, который использует IMyCollection. Не совсем то, что я считаю решением моей цели.

+0

Поскольку вы используете 'var', для чего вам нужно, чтобы оно было короче? Вы также используете список и просто вызываете метод «AsReadOnly» – DevEstacion

+0

«Я хочу сохранить нажатия клавиш», кажется, что это неправильная причина для изменения вашей объектной модели - если то, что вы пытались, было успешным, вы запретили бы мне использовать любые 'IReadOnlyList >', который не был 'IMyCollection' во всех местах, которые я назвал' IMyCollection', хотя вы намерены, что они идентичны. –

+0

@DevEstacion Вы сосредоточены на простом примере, предназначенном только для демонстрации роли, которую я пытаюсь сделать. В реальном мире этот полный тип должен набираться во много раз как возвращаемые значения функции, переданные как параметры другим функциям, кастинг при извлечении из пакетов данных и т. Д. –

ответ

4

Как сильно вы этого хотите?

Вы можете вручную реализовать свой собственный класс-оболочку.

public interface IMyCollection : IReadOnlyList<IReadOnlyList<MyObject>> 
{ 
} 

public class MyCollectionImpl : IMyCollection 
{ 
    private readonly IReadOnlyList<IReadOnlyList<MyObject>> _wrappedCollection; 
    public MyCollectionImpl(IReadOnlyList<IReadOnlyList<MyObject>> wrappedCollection) 
    { 
     _wrappedCollection = wrappedCollection; 
    } 

    public int Count 
    { 
     get 
     { 
      return _wrappedCollection.Count; 
     } 
    } 

    public IReadOnlyList<MyObject> this[int index] 
    { 
     get 
     { 
      return _wrappedCollection[index]; 
     } 
    } 

    public IEnumerator<IReadOnlyList<MyObject>> GetEnumerator() 
    { 
     return _wrappedCollection.GetEnumerator(); 
    } 

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() 
    { 
     return _wrappedCollection.GetEnumerator(); 
    } 
} 

Тогда вы просто создать экземпляр этого:

public class MyObject 
    { 
     public static IMyCollection GetCollection() 
     { 
      var a = new List<MyObject>(); 
      a.Add(new MyObject()); 

      var b = new List<IReadOnlyList<MyObject>>(); 
      b.Add(a.AsReadOnly()); 

      return new MyCollectionImpl(b.AsReadOnly()); 
     } 
    } 

Это, кажется, как много дополнительной работы, но я бы на самом деле считаю, что это шаг рефакторинга.

Я считаю, что необходимость передавать типы, составленные из сложного набора общих параметров, на самом деле является неприятным запахом в вашем коде.

Спросите себя, что вы на самом деле используете IMyCollection? Могли бы вы добавить некоторые специальные методы для этого интерфейса, чтобы упростить его использование?

После того как вы создали свой собственный класс MyCollectionImpl, вы можете добавить несколько методов в свой интерфейс IMyCollection, чтобы упростить его использование. В какой-то момент вы даже можете выйти на сцену, где вы можете прекратить демонстрацию интерфейса <IReadonlyList<IReadonlyList<MyObject>>.

+1

Это в значительной степени то, что я имел в виду. Это действительно рефакторинг для моего кода, один небольшой шаг за раз добавление функций по мере необходимости. Мой вопрос был предназначен для того, чтобы найти шаг между использованием сложного типа и вашей реализацией MyCollectionImpl. Спасибо за ответ! –

3

Это не имеет никакого отношения к ковариации. IMyCollection наследует от IReadOnlyList<IReadOnlyList<MyObject>>, поэтому вы можете сделать экземпляр IMyCollection до IReadOnlyList<IReadOnlyList<MyObject>>, но не наоборот.

Если у вас есть какие-то пользовательские преобразования, вы можете создать тип вместо короткого имени и объявить преобразование от IReadOnlyList<IReadOnlyList<MyObject>> к вашему типу, используя operator overloading. Это действительно кажется ненужным и необычным способом использования перегрузки операторов, но это единственный способ сделать то, что вы хотите достичь.

Смежные вопросы