如何声明c#匿名类型而不创建它的实例?

本文关键字:创建 实例 类型 何声明 声明 | 更新日期: 2023-09-27 18:18:16

有没有更好的方法可以声明匿名类型,而不需要创建它的实例?

var hashSet = new [] { new { Name = (string)null } }.Take(0).ToHashSet(); // HashSet<T>
using (new Scope())
{
    hashSet.Add(new { Name = "Boaty" });
    hashSet.Add(new { Name = "McBoatface" });
}
using (new AnotherScope())
{
    return names.Where(x => hashSet.Contains(new { x.Name }));
}

我不喜欢上面第一行中采用的看起来很粗糙的方法,但它确实允许我稍后在不同范围内使用HashSet。

编辑:第二个更全面的例子:

private IEnumerable<Person> _people;
public IEnumerable<Person> People()
{
    HashSet<T> hashSet;
    using (var new Scope())
    {
        // load a filter from somewhere else (oversimplified here to a single literal objects of an anonymous type)
        hashSet = new []
        {
            new { FirstName = "Boaty", LastName = "McBoatface" },
        }.ToHashSet();
    }
    using (var new AnotherScope())
    {
         return _people.Where(x => hashSet.Contains(new { FirstName = x.Nombre, LastName = x.Apellido }));
    }
}

如何声明c#匿名类型而不创建它的实例?

实际上没有办法做到这一点,一个匿名对象总是有一些对象初始化(这是通过使用new)。

匿名类型是一种设置和忘记,这意味着使用它们一次-通常在一小段代码中,例如linq表达式-然后忘记它们曾经存在过。

然而,你应该问自己为什么你需要这个。当你需要你的列表通过你的类给它的实体一个名字。在不同的作用域中使用相同的匿名类型有什么好处?要清晰准确。因此,每个开发人员都了解您的列表包含的内容以及他/她可以从中接受的内容。

因此,您最好使用(私有)struct,这也可以在您的方法中使用。

class CyClass
{
    private struct Person { public string Name; }
    
    HashSet<Person> hashSet = new HashSet<Person>();
    ...
        using (var firstScope = new Scope())
        {
            hashSet.Add(new Person { Name = "Boaty" });
            hashSet.Add(new Person { Name = "McBoatface" });
        }
    
        using (var secondScope = new AnotherScope())
        {
            return names.Where(x => hashSet.Contains(new Person{ x.Name }));
        }
}

MSDN明确指出:

如果必须存储查询结果或将其传递到方法边界之外,请考虑使用普通的命名结构或类而不是匿名类型

然而,我不会像第二段中描述的那样将其限制在方法边界。

编辑:要回答你的问题,是否有可能在不实例化的情况下创建匿名类型,请参阅来自MSDN的这句话:

通过使用new操作符和an来创建匿名类型对象初始化器

EDIT2:从c# 7开始,你可以在列表中使用元组。然而,一个元组至少有两个属性,所以你的第一个例子在这里行不通:

var myList = new List<(string FirstName, string LastName)>();
myList.Add(("Boaty", "McBoatface"));

现在您可以检查您的其他列表是否包含这样的元组:

var contained = anotherList.Contains(("Boaty", "McBoatface"));

您可以创建匿名类型的变量而无需创建该类型的实例。

public static T DefaultReturnValue<T>(this Action<T> _) => default;
var initialVariable = DefaultReturnValue(() => new { Name = "x" });

来自lambda的操作永远不会执行。DefaultReturnValue只提取返回类型

你可以稍后给这个变量赋值。

initialVariable = new { Name = "y" };

对于OP中的第二个示例使用此方法,可以声明初始HashSet变量,而无需创建HashSet的多余实例:

var hashSet = DefaultReturnValue(() => new [] { new { Name = (string)null } }.ToHashSet());