Подтвердить что ты не робот

С#: Есть ли способ LINQ для создания массива объектов, заданного массивом параметров конструктора?

В качестве примера, скажем, у меня есть массив имен, и я хочу создать массив объектов Person, вызывая конструктор, который принимает string name.

class Person()
{
    public string Name { get; set; }

    public Person(string name)
    {
        Name = name;
    }
}

...

static void Main()
{
    string[] names = {"Peter", "Paul", "Mary"};
    Person[] people;

    /*  I could do this but I'm wondering if there a better way. */
    List<Person> persons = new List<Person>();
    foreach(string name in names)
    {
        persons.Add(new Person(name));
    }

    people = persons.ToArray();
}

Я слишком долго застрял в мире .Net 2.0, и я пытаюсь модернизировать свой текущий простоя...

4b9b3361

Ответ 1

// names is string[]
Person[] people = names.Select(s => new Person(s)).ToArray();

Пояснение:

Enumerable.Select - это метод LINQ для проектирования. То есть, взяв последовательность Foo и проецируя их на Bar через некоторое правило Func<Foo, Bar>, которое ест Foo и выплевывает Bar s. Таким образом,

names.Select(s => new Person(s))

- проекция последовательности names типа IEnumerable<string> на последовательность типа IEnumerable<Person>. Если вы знаете функциональное программирование, он играет роль map.

Теперь здесь есть тонкий момент, который стоит понять; это почти наверняка один из самых важных, но легко понятых аспектов LINQ. Это концепция отсроченного исполнения. Когда мы говорим

IEnumerable<Person> persons = names.Select(s => new Person(s));

это фактически не выполняет проекцию (т.е. еще не создает экземпляры Person, построенные с использованием string in names в качестве параметров конструктора). Вместо этого он создает что-то, что фиксирует правило проецирования последовательности names в последовательность Person. Это только тогда, когда это правило (известное как итератор) фактически выполняется, происходит проецирование.

Один из способов вызвать это выполнение - использовать метод Enumerable.ToArray, который в основном говорит о повторении последовательности и возвращает мне результаты в виде массива.

Существуют и другие способы, чтобы выполнение выполнялось. Например

IEnumerable<Person> persons = names.Select(s => new Person(s)); 
foreach(Person p in persons) {
    Console.WriteLine(p.Name);
}

или

IEnumerable<Person> persons = names.Select(s => new Person(s)); 
Person p = persons.First();

который выполнил бы "первую" проекцию (т.е. new Person(names[0])) и присвоил результат p.

Конечно, это даже не означает, что именно

s => new Person(s)

есть. Это выражение лямбда, и вы можете познакомиться с ними в моем ответе на Как это выражение LINQ работает?.

Ответ 2

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

Представьте, что у вас есть класс с именем человека и названием задания, и вы хотите заполнить этот объект:

public class Employee
{
   private string name;
   private string jobTitle;

   public Employee(){}
   public Employee(string name, string job)
   {
     this.name = name;
     this.jobTitle = job;
   }

  //  getters + setters...
}

Тогда вы сделали бы

var IQueryable<Employee> list = from p in context.Persons 
                                join j in context.Jobs
                                  on p.jobId == j.jobId
                                select new Employee(p.Name, j.Title);

Затем вы пройдете через список, чтобы получить экземпляры