任何语法糖,用于实例化具有来自 IEnumerable <T>的属性的对象



我正在实例化一个具有来自IEnumerable属性的对象。直接的方法是

IEnumerable<string> source = ...
var instance = new X(
source.First(), 
source.Skip(1).First(), 
source.Skip(2).First(),
...
);

其中X是一个类,其构造函数接受多个形参。

可以工作,但感觉这是一个常见的场景(例如使用通用存储层获取数据并实例化特定的记录类型),应该是更清晰的方式。

我考虑使用.ToList()创建一个列表,然后使用索引器访问属性,但这计算了整个Enumerable,我觉得这里没有必要。

是否有更简洁的方法?我在想象一个枚举方法,这将允许我.MoveNext()&.Current方法,这将允许我O(1)访问和没有不必要的分配—但是使用一些语法糖使其美观

看起来你正在尝试从序列中取前N个值,对于N的某个值

如果X(...)占用params string[],那么你可以只使用source.Take(N).ToArray();因为无论如何我们都要构建数组,所以这没有特别的额外开销。

如果X(...)接受N单独的string参数,那么您确实需要展开它,但是多次迭代该序列会很尴尬。它可能很丑,但我可能会在这里使用自定义的东西:

string a, b, c;
using (IEnumerator<string> iter = source.GetEnumerator())
{
a = iter.Next();
b = iter.Next();
c = iter.Next();
}
return new X(a, b, c);
static class Utils
{
public static T Next<T>(this IEnumerator<T> source)
{
if (!source.MoveNext()) Throw();
return source.Current;
static void Throw() => throw new InvalidOperationException("Missing element from sequence");
}
}

如果您不介意将序列延长一点(到构造函数调用中),您也可以将构造函数移动到using中:

using IEnumerator<string> iter = source.GetEnumerator();
return new X(iter.Next(), iter.Next(), iter.Next());

可以通过activator.createinstanc<T>传递参数详见:https://learn.microsoft.com/en-us/dotnet/api/system.activator.createinstance?redirectedfrom=MSDN&view=net-7.0#System_Activator_CreateInstance_System_Type_System_Object___

试试这个:

using System;
using System.Collections.Generic;
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
public Person(string firstName, string lastName, int age)
{
FirstName = firstName;
LastName = lastName;
Age = age;
}
}
class Program
{
static void Main(string[] args)
{
List<object> constructorArgs = new List<object>() { "David", "Božjak", 30 };
Person p = (Person)Activator.CreateInstance(typeof(Person), constructorArgs.ToArray());
Console.WriteLine($"{p.FirstName} {p.LastName} is {p.Age} years old.");
}
}

最新更新