创建分层匿名类型

3
有没有办法创建引用自身实例的匿名类型?
var root = new { Name = "Root", Parent = ??? };
var child = new { Name = "Child", Parent = root };
var childOfChild = new { Name = "Grand child", Parent = child };

例如,我们可以从自身引用委托:
Action run = null;
run = () => run();

另一个例子,我们可以创建匿名类型的通用堆栈:

static Stack<T> CreateStack<T>(params T[] values)
{
    var stack = new Stack<T>();

    foreach (var value in values)
        stack.Add(value);

    return stack;
}

你能想到任何引用其自身的匿名类型的方法吗?

2个回答

9
在C#中,匿名类型是不可变的。因此,在对象创建之前,它们的所有字段值必须存在,并且永远不会改变。因此,在C#中不可能直接创建循环引用的匿名类型。
在VB中,匿名类型是可变的;你可以想出一些方法来实现循环引用。
也许有一种方法可以使匿名类型间接地引用自己,例如包含一个委托,当调用时返回匿名类型的实例。我没有立即想到容易实现这样做的方法,但我也没有找到证明这样做不可能的证据。请思考一下并看看你能想出什么!
我假设这个问题只是为了娱乐目的。如果你想创建一个循环引用的对象,请创建一个名义类型。

我的结构是不可变的。根节点的父节点为空,直接根节点的子节点引用根节点等等。 - Konstantin Spirin
我已经为了清晰度重命名了问题。 - Konstantin Spirin

1

似乎C#编译器会拒绝递归推断类型。以这段示例代码为例:

(来自@Eric:正确;类型推断引擎要求在推断lambda的“输出”类型之前,必须知道lambda的所有“输入”类型)

public void Run()
{
  var k = Generator((str, parent) => new {
    Name = str,
    Parent = parent
  });
}

public Func<string, T, T> Generator<T>(Func<string, T, T> generator)
{
  return (str, obj) => generator(str, obj);
}

这段代码片段无法编译,因为编译器无法推断要与Generator<T>一起使用的<T>... 因此我认为这是不可能的。

我已经创建了一个新的类,并在SO上询问是否我的原始任务是不可能完成的。 - Konstantin Spirin
有趣的想法,使用生成器! - Konstantin Spirin
正确;类型推断引擎要求在推断 lambda 的“输出”类型之前,必须已知所有 lambda 的“输入”类型。 - Eric Lippert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接