Неявное преобразование над коллекцией - PullRequest
9 голосов
/ 09 июня 2011

На этой неделе я столкнулся с проблемой неявных преобразований в C # для коллекций.Хотя это (использование implicit), возможно, не является нашим последним подходом, я хотел, по крайней мере, закончить код, чтобы предложить команде в качестве опции.Я свел проблему к следующему примеру:

У меня есть два класса в моем примере: один, представляющий бизнес-объект (Foo), и другой, представляющий версию клиента (View Object) этого бизнес-элемента (FooVO), как определено ниже ...

public class Foo
{
    public string Id {get; set;}

    public string BusinessInfo {get; set;}
}

public class FooVO
{
    public string Id {get; set;}

    public static implicit operator FooVO( Foo foo )
    {
        return new FooVO { Id = foo.Id };
    }
}

Моя проблема в том, что у меня есть список объектов Foo, и я хочу преобразовать их в список объектов FooVO, используя мой неявный оператор.

List<Foo> foos = GetListOfBusinessFoos(); // Get business objects to convert

Я пытался

List<FooVO> fooVOs = foos; // ERROR

и

List<FooVO> fooVOs = (List<FooVO>) foos; // ERROR

и даже

List<FooVO> fooVOs = foos.Select( x => x ); // ERROR

Я знаю, что могу сделать это в цикле, но я надеялся на простой (LINQ?) способ конвертировать объекты в одном кадре.Есть идеи?

Заранее спасибо.

Редактировать Исправлена ​​опечатка в примере

Ответы [ 4 ]

22 голосов
/ 09 июня 2011

Такой вопрос задают почти каждый день на SO.Вы не можете сделать это, потому что это нарушает безопасность типов:

List<Giraffe> g = new List<Giraffe>();
List<Animal> a = g; // Should this be legal?
a.Add(new Tiger()); // Nope; we just added a tiger to a list of giraffes.

В C # 4.0 вы можете неявно конвертировать из IEnumerable<Giraffe> в IEnumerable<Animal>, потому что не существует метода «Добавить», чтобы все испортить.Но вы никогда не сможете выполнить «ковариантное» преобразование, как если бы преобразование типов элементов было пользовательским .Это должна быть ссылка или личность преобразование.

Вам нужно будет создать второй список и скопировать их по одному за раз.Или используйте вспомогательные методы LINQ, такие как Select и ToList, чтобы выполнить эту работу за вас.

Имя требуемой концепции системы типов - "ковариация";ковариантные отношения - это те, в которых вы рассуждаете: «Жирафы - это животные, поэтому последовательности жирафов - это последовательности животных».Если эта тема вас интересует, вы можете прочитать о том, как мы добавили ковариацию (и контравариантность) в C # 4.0 здесь:

http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx

Начните снизу.

19 голосов
/ 09 июня 2011

Причина, по которой ваши примеры не работают, заключается в том, что вы пытаетесь присвоить IEnumerable<FooVO> для List<FooVO>.Следующее должно работать.

 List<FooVO> fooVos = foos.Select<Foo,FooVO>(x => x).ToList();
9 голосов
/ 09 июня 2011
List<FooVO> d = new List<FooVO>(foos.Select(x => (FooVO)x)); 

У меня работает.

6 голосов
/ 09 июня 2011

Использовать метод ConvertAll, передавая static implicit operator FooVO( Foo foo ) в качестве аргумента

List<FooVO> fooVOs = foos.ConvertAll<FooVO>(FooVO.FooVO);
...