【问题标题】:Creating a Stack<T> with anonymous type创建具有匿名类型的 Stack<T>
【发布时间】:2010-08-07 07:27:30
【问题描述】:

我有这样的 Foo 类:

 class Foo
 {
  public int id{get;set;}
  public IEnumerable<Foo> Childs;
       //some other properties
 }

现在我想在 Foo-Object 及其所有子对象上处理一些业务逻辑,如下所示:

 public void DoSomeWorkWith(Foo x)
 {
  var firstItem = new {level = 0, item = x};
  var s = new Stack<?>(?); //What type to use?
  s.Push(firstItem);
  while(s.Any())
  {
    var current = s.Pop();
    DoSomeBusiness(current.item);
    DoSomeMoreBusiness(current.item);
    Log(current.level, current.item.id);
    foreach(Foo child in current.item.Childs)
       s.Push(new {level = current.level + 1, item = child});
   }
}

我需要跟踪孩子的(相对)水平/深度。 如何为匿名类型创建Stack&lt;T&gt;?当然我可以创建一个简单的类而不是匿名类型(或更复杂的递归函数),但是如何在没有额外类的情况下解决这个问题呢?

【问题讨论】:

  • 您能否格式化您的代码:)
  • Childs 读起来有点奇怪,因为 'child' 的英文复数是 'children' :)

标签: c# .net anonymous-types


【解决方案1】:

怎么样:

public static Stack<T> CreateEmptyStack<T>(T template) {
    return new Stack<T>();
}
...
var stack = CreateEmptyStack(firstItem);

这使用泛型类型推断来处理T

【讨论】:

    【解决方案2】:

    你可以把它放到这样的方法中:

    public Stack<T> CreateStackWithInitialItem<T>(T initialItem)
    {
        var s = new Stack<T>();
        s.Push(initialItem);
        return s;
    }
    

    然后像这样使用它:

    public void DoSomeWorkWith(Foo x)
    {
        var s = CreateStackWithInitialItem(new {level = 0, item = x});
        while(s.Any())
        {
            ...
        }
    }
    

    【讨论】:

      【解决方案3】:

      使用元组 (System.Tuple&lt;&gt;) 代替匿名类型怎么样?

      public void DoSomeWorkWith(Foo x)
      {
          var firstItem = new Tuple<int, Foo>(0, x);
          var s = new Stack<Tuple<int, Foo>>();
          s.Push(firstItem);
          while (s.Any())
          {
              var current = s.Pop();
              DoSomeBusiness(current.Item2);
              DoSomeMoreBusiness(current.Item2);
              Log(current.Item1, current.Item2.id);
              foreach (Foo child in current.Item2.Childs)
                  s.Push(new Tuple<int, Foo>(current.Item1 + 1, child));
          }
      }
      

      尽管这不是动态对象的主要用例(通过您了解设计时涉及的所有类型),您也可以使用System.Dynamic.ExpandoObject。 如果这样做,请务必测试由于开销导致的性能差异。

      public void DoSomeWorkWith(Foo x)
      {
          dynamic firstItem = new ExpandoObject();
          firstItem.level = 1;
          firstItem.item = x;
      
          var s = new Stack<dynamic>();
          s.Push(firstItem);
          while (s.Any())
          {
              var current = s.Pop();
              DoSomeBusiness(current.item);
              DoSomeMoreBusiness(current.item);
              Log(current.level, current.item.id);
              foreach (Foo child in current.item.Childs)
              {
                  dynamic next = new ExpandoObject();
                  next.level = current.level + 1;
                  next.item = child;
                  s.Push(next);
              }
          }
      }
      

      【讨论】:

        【解决方案4】:

        您可以通过使用递归来简化代码,而不是将内容推送到临时堆栈和临时对象上。例如:

        // (If you're not using C# 4, you can replace the default level with a function
        // overload or just remove the default value)
        
        void ProcessFooRecursive(Foo foo, int level = 0) 
        {
            DoSomeBusiness(foo);
            DoSomeMoreBusiness(foo);
            Log(level, foo.id);
        
            var newDepth = level + 1;
            foreach (var child in foo.Childs)
            {
                ProcessFooRecursive(child, newDepth);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-04-06
          • 1970-01-01
          • 2016-01-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-12-22
          相关资源
          最近更新 更多