Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何为复合模式实现IEnumerator接口?_C#_Generics_Interface - Fatal编程技术网

C# 如何为复合模式实现IEnumerator接口?

C# 如何为复合模式实现IEnumerator接口?,c#,generics,interface,C#,Generics,Interface,我有一个遵循复合模式的对象集合。它们形成了一个我想用IEnumerator遍历的树结构。我正在翻译《头先设计模式》一书中的一些java代码。我已经实现了两个实现IEnumerator接口的类:CompositeIterator和NullIterator 是我想翻译成C的java代码 另外,这是我的,当我只需要调用MoveNext和Current来遍历整个树结构时 现在,我的代码没有进入涉及迭代器的while循环,我想在控制台上打印素食菜单项对象 这是我的密码: using System; usi

我有一个遵循复合模式的对象集合。它们形成了一个我想用IEnumerator遍历的树结构。我正在翻译《头先设计模式》一书中的一些java代码。我已经实现了两个实现IEnumerator接口的类:CompositeIterator和NullIterator

是我想翻译成C的java代码

另外,这是我的,当我只需要调用MoveNext和Current来遍历整个树结构时

现在,我的代码没有进入涉及迭代器的while循环,我想在控制台上打印素食菜单项对象

这是我的密码:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Iterator
{
  class Program
  {
    static void Main(string[] args)
    {
      MenuComponent pancakeHouseMenu = new Menu("PANCAKEHOUSE MENU", "Breakfast");
      MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch");
      MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner");
      MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!");

      MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");

      allMenus.Add(pancakeHouseMenu);
      allMenus.Add(dinerMenu);
      allMenus.Add(cafeMenu);

      pancakeHouseMenu.Add(new MenuItem("K&B Pancake breakfast", "pancakes with scrambled eggs, and toast", true, 2.99));
      pancakeHouseMenu.Add(new MenuItem("Regular Pancake breakfast", "pancakes with fried eggs, sausage", false, 2.99));

      dinerMenu.Add(new MenuItem("Veggie burguer and air fries", "Veggie burguer on a whole wheat bun, lettuce, tomato and fries", true, 3.99));
      dinerMenu.Add(new MenuItem("Soup of the day", "Soup of the day with a side salad", false, 3.69));

      dinerMenu.Add(dessertMenu);

      dessertMenu.Add(new MenuItem("Apple pie", "Apple pie with a flakey crust, topped with vanilla ice cream", true, 1.59));

      cafeMenu.Add(new MenuItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99));
      cafeMenu.Add(new MenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99));

      Waitress waitress = new Waitress(allMenus);
      waitress.PrintVegetarianMenu();
    }
  }

  class Waitress
  {
    private MenuComponent AllMenus { get; set; }

    public Waitress(MenuComponent allMenus)
    {
      AllMenus = allMenus;
    }

    public void PrintMenu()
    {
      AllMenus.Print();
    }

    public void PrintVegetarianMenu()
    {
      CompositeIterator<MenuComponent> iterator = (CompositeIterator<MenuComponent>)AllMenus.CreateIterator();
      Console.WriteLine("VEGATARIAN MENU");

      // this loop is never entered
      while (iterator.MoveNext())
      {
        Console.WriteLine("inside while loop");
        MenuComponent menuComponent = (MenuComponent)iterator.Current;
        Console.WriteLine(menuComponent.Name);

        try
        {
          if (menuComponent.Vegetarian)
          {
            menuComponent.Print();
          }
        }
        catch (NotSupportedException e)
        {
          Console.WriteLine("Operation not supported.");
        }
      }
    }
  }

  /*
  Methods of MenuComponent class are virtual, because we sometimes want to use the default behavior. The CreateIterator method is abstract.
  */
  abstract class MenuComponent
  {
    // Composite methods
    public virtual void Add(MenuComponent menuComponent)
    {
      throw new NotSupportedException();
    }

    public virtual void Remove(MenuComponent menuComponent)
    {
      throw new NotSupportedException();
    }

    public virtual MenuComponent GetChild(int i)
    {
      throw new NotSupportedException();
    }
    // End of composite methods

    // Operation methods
    public virtual string Name
    {
      get
      {
        throw new NotSupportedException();        
      }
      set
      {
        throw new NotSupportedException();
      }
    }

    public virtual string Description
    {
      get
      {
        throw new NotSupportedException();        
      }
      set
      {
        throw new NotSupportedException();
      }
    }

    public virtual bool Vegetarian
    {
      get
      {
        throw new NotSupportedException();        
      }
      set
      {
        throw new NotSupportedException();
      }
    }

    public virtual double Price
    {
      get
      {
        throw new NotSupportedException();
      }
      set
      {
        throw new NotSupportedException();
      }
    }

    public virtual void Print()
    {
      throw new NotSupportedException();
    }
    // End of operation methods

    public abstract IEnumerator CreateIterator();
  }

  public sealed class CompositeIterator<T> : IEnumerator<T> {
    private readonly Stack<IEnumerator<T>> Stack = new Stack<IEnumerator<T>>();

    public CompositeIterator(IEnumerator<T> initial)
    {
      Stack.Push(initial);
    }

    public bool MoveNext()
    {
      while (Stack.Any())
      {
        if (!Stack.Peek().MoveNext())
        {
          Stack.Pop().Dispose();
          continue;
        }
        var tmp = Current as IEnumerable<T>;
        if (tmp != null) { Stack.Push(tmp.GetEnumerator()); }
      }
      return false;
    }

    public void Reset() { throw new NotSupportedException(); }

    public T Current => Stack.Peek() != null ? Stack.Peek().Current : default(T);

    object IEnumerator.Current => Current;

    public void Dispose()
    {
      if (!Stack.Any()) { return; }
      try {
        foreach (var x in Stack) {
          x.Dispose();
        }
      } catch { }
    }
  }

  public sealed class NullIterator<T> : IEnumerator<T> {
    public NullIterator() {}

    public bool MoveNext()
    {
      return false;
    }

    public void Reset() { throw new NotSupportedException(); }

    public T Current
    {
      get
      {
        return default(T);
      }
    }

    object IEnumerator.Current => Current;

    public void Dispose()
    {
      return;
    }
  }

  // This is a tree leaf
  class MenuItem : MenuComponent
  {
    public override string Name { get; set; }
    public override string Description { get; set; }
    public override bool Vegetarian { get; set; }
    public override double Price { get; set; }

    public MenuItem(string name, string description, bool vegetarian, double price)
    {
      Name = name;
      Description = description;
      Vegetarian = vegetarian;
      Price = price;
    }

    public override void Print()
    {
      Console.Write("  " + Name);
      if (Vegetarian)
      {
        Console.Write("(v)");
      }
      Console.Write(", " + Price);
      Console.Write("     -- " + Description);
    }

    public override IEnumerator CreateIterator()
    {
      return new NullIterator<MenuItem>();
    }
  }

  // This is a tree node
  class Menu : MenuComponent
  {
    public List<MenuComponent> MenuComponents;
    public override string Name { get; set; }
    public override string Description { get; set; }

    public Menu(string name, string description)
    {
      Name = name;
      Description = description;
      MenuComponents = new List<MenuComponent>();
    }

    public override void Add(MenuComponent menuComponent)
    {
      MenuComponents.Add(menuComponent);
    }

    public override void Remove(MenuComponent menuComponent)
    {
      MenuComponents.Remove(menuComponent);
    }

    public override MenuComponent GetChild(int i)
    {
      return MenuComponents[i];
    }

    // we have to use recursion to print all the hierarchy
    public override void Print()
    {
      Console.Write("\n" + Name);
      Console.WriteLine(", " + Description);
      Console.WriteLine("--------------");

      IEnumerator iterator = MenuComponents.GetEnumerator();

      while(iterator.MoveNext())
      {
        MenuComponent menuComponent = (MenuComponent)iterator.Current;
        menuComponent.Print();
        Console.Write("\n");
      }
    }

    public override IEnumerator CreateIterator()
    {
      return new CompositeIterator<MenuComponent>(MenuComponents.GetEnumerator());
    }
  }
}

这是我在不创建自己的迭代器的情况下最接近您想要的。我不觉得有必要重新编码dotnet框架中已经存在的东西

class Program
{
    static void Main(string[] args)
    {
        //var all = new Menu("ALL SECTIONS", "All menu sections");

        var pancakeHouseMenu = new Menu("PANCAKEHOUSE MENU", "Breakfast", 
            new MenuSection("PANCAKES", "Breakfast Pancakes Selection",
                new MenuItem("K&B Pancake breakfast", "pancakes with scrambled eggs, and toast", true, 2.99m),
                new MenuItem("Regular Pancake breakfast", "pancakes with fried eggs, sausage", false, 2.99m)));

        var dinnerMenu = new Menu("DINNER MENU", "Lunch",
            new MenuSection("","",
                new MenuItem("Veggie burger and air fries", "Veggie burguer on a whole wheat bun, lettuce, tomato and fries", true, 3.99m),
                new MenuItem("Soup of the day", "Soup of the day with a side salad", false, 3.69m)));

        var cafeMenu = new Menu("CAFE MENU", "Dinner",
            new MenuSection("", "",
                new MenuItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99m),
                new MenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99m)),
            new MenuSection("DESSERT MENU", "Dessert of course!",
                new MenuItem("Apple pie", "Apple pie with a flakey crust, topped with vanilla ice cream", true, 1.59m)));

        var waiter = new Waitress(pancakeHouseMenu, dinnerMenu, cafeMenu);

        //waiter.Print();
        //waiter.PrintVegenerian();


        WriteFileAndOpenNotepad(waiter.ToString());
        WriteFileAndOpenNotepad(waiter.ToVegetarianString());
    }

    static void WriteFileAndOpenNotepad(string text)
    {
        var fn = Path.GetTempFileName();
        fn=Path.ChangeExtension(fn, ".txt");
        File.WriteAllText(fn, text);
        Process.Start(fn);
    }
}




public abstract class MenuComponent
{
    public string Description { get; private set; }
    public string Name { get; private set; }
    protected MenuComponent(string name, string description)
    {
        this.Name=name;
        this.Description=description;
    }

    public abstract override string ToString();
    public void Print()
    {
        Console.WriteLine(ToString());
    }
}
public class MenuItem : MenuComponent
{
    public MenuItem(string name, string description, bool vegeterian, decimal price)
        : base(name, description)
    {
        this.Price=price;
        this.Vegetarian=vegeterian;
    }
    public decimal Price { get; set; }
    public bool Vegetarian { get; set; }

    public override string ToString()
    {
        //Use 28 columns for the item name
        return string.Format("{0,28}{1}, {2}     -- {3}",
            Name, Vegetarian ? "(v)" : "   ", Price, Description);
    }

}

public class MenuSection : MenuComponent
{
    public MenuSection(string name, string description, params MenuItem[] items)
        : this(name, description, items as IEnumerable<MenuItem>)
    { }

    public MenuSection(string name, string description, IEnumerable<MenuItem> items) : base(name, description)
    {
        this.Items=new List<MenuItem>(items);
    }

    public List<MenuItem> Items { get; private set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine();
        if(Name.Length>0)
        {
            sb.AppendFormat("{0}, {1}", Name, Description);
            sb.AppendLine();
            sb.AppendLine("--------------");
        }
        foreach(var item in Items)
        {
            sb.AppendLine();
            sb.AppendLine(item.ToString());
        }
        return sb.ToString();

    }

    public MenuSection VegeterianSections
    {
        get
        {
            var veg = Items.Where((item) => item.Vegetarian);
            return new MenuSection(Name, Description, veg);
        }
    }
}

public class Menu : MenuComponent
{
    public Menu(string name, string description, IEnumerable<MenuSection> sections)
        : base(name, description)
    {
        this.MenuSections=new List<MenuSection>(sections);
    }
    public Menu(string name, string description, params MenuSection[] sections)
        : this(name, description, sections as IEnumerable<MenuSection>)
    { }

    public List<MenuSection> MenuSections { get; private set; }

    public override string ToString()
    {
        var sb = new StringBuilder();
        sb.AppendLine();
        sb.AppendFormat("[{0}, {1}]", Name, Description);
        sb.AppendLine();
        sb.AppendLine("==============");
        foreach(var section in MenuSections)
        {
            sb.AppendLine();
            sb.AppendLine(section.ToString());
        }
        return sb.ToString();
    }

    public Menu VegeraterianMenu
    {
        get
        {
            return new Menu(Name, Description, MenuSections.Select((section)=> section.VegeterianSections));
        }
    }
}
public class Waitress
{
    public Waitress(params Menu[] all)
    {
        this.AllMenus=new List<Menu>(all);
        this.VegeratianMenu=all.Select((menu)=>menu.VegeraterianMenu).ToList();
    }
    public IList<Menu> AllMenus { get; private set; }
    public IList<Menu> VegeratianMenu { get; private set; }

    public override string ToString()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("*** A L L  I T E M S ***");
        foreach(var item in AllMenus)
        {
            sb.AppendLine("************************");
            sb.AppendLine(item.ToString());
        }
        return sb.ToString();
    }

    public string ToVegetarianString()
    {
        StringBuilder sb = new StringBuilder();
        sb.AppendLine("*** V E G  I T E M S ***");
        foreach(var item in VegeratianMenu)
        {
            sb.AppendLine("************************");
            sb.AppendLine(item.ToString());
        }
        return sb.ToString();
    }
    public void Print()
    {
        Console.WriteLine(ToString());
    }
    public void PrintVegenerian()
    {
        Console.WriteLine(ToVegetarianString());
    }
}

在与C freenode IRC频道的人联系后,其中一人给了我一个比书中更好的解决方案,我在这里得到了答案。这就是代码,有了这个答案,我希望我清楚地知道我想要什么:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;

namespace Iterator
{
  class Program
  {
    static void Main(string[] args)
    {
      MenuComponent pancakeHouseMenu = new Menu("PANCAKEHOUSE MENU", "Breakfast");
      MenuComponent dinerMenu = new Menu("DINER MENU", "Lunch");
      MenuComponent cafeMenu = new Menu("CAFE MENU", "Dinner");
      MenuComponent dessertMenu = new Menu("DESSERT MENU", "Dessert of course!");

      MenuComponent allMenus = new Menu("ALL MENUS", "All menus combined");

      allMenus.Add(pancakeHouseMenu);
      allMenus.Add(dinerMenu);
      allMenus.Add(cafeMenu);

      pancakeHouseMenu.Add(new MenuItem("K&B Pancake breakfast", "pancakes with scrambled eggs, and toast", true, 2.99));
      pancakeHouseMenu.Add(new MenuItem("Regular Pancake breakfast", "pancakes with fried eggs, sausage", false, 2.99));

      dinerMenu.Add(new MenuItem("Veggie burguer and air fries", "Veggie burguer on a whole wheat bun, lettuce, tomato and fries", true, 3.99));
      dinerMenu.Add(new MenuItem("Soup of the day", "Soup of the day with a side salad", false, 3.69));

      dinerMenu.Add(dessertMenu);

      dessertMenu.Add(new MenuItem("Apple pie", "Apple pie with a flakey crust, topped with vanilla ice cream", true, 1.59));

      cafeMenu.Add(new MenuItem("Vegetarian BLT", "(Fakin') Bacon with lettuce & tomato on whole wheat", true, 2.99));
      cafeMenu.Add(new MenuItem("BLT", "Bacon with lettuce & tomato on whole wheat", false, 2.99));

      cafeMenu.Add(dessertMenu);

      Waitress waitress = new Waitress(allMenus);
      waitress.PrintVegetarianMenu();
    }
  }

  class Waitress
  {
    private MenuComponent AllMenus { get; set; }

    public Waitress(MenuComponent allMenus)
    {
      AllMenus = allMenus;
    }

    public void PrintMenu()
    {
      AllMenus.Print();
    }

    public void PrintVegetarianMenu()
    {
      Console.WriteLine("VEGATARIAN MENU");

      foreach (MenuComponent menuComponent in AllMenus)
      {
        try
        {
          if (menuComponent.Vegetarian)
          {
            menuComponent.Print();
            Console.Write("\n");
          }
        }
        catch (NotSupportedException)
        {
          Console.WriteLine("Operation not supported.");
        }
      }
    }
  }

  abstract class MenuComponent : IEnumerable<MenuComponent>
  {
    // Composite methods
    public abstract void Add(MenuComponent menuComponent);

    public abstract void Remove(MenuComponent menuComponent);

    public abstract MenuComponent GetChild(int i);
    // End of composite methods

    // Operation methods
    public virtual string Name { get; set; }

    public virtual string Description { get; set; }

    public virtual bool Vegetarian { get; set; }

    public virtual double Price { get; set; }

    public abstract void Print();

    public abstract IEnumerator<MenuComponent> GetEnumerator();

    IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
  }

  /// This is a tree leaf
  class MenuItem : MenuComponent
  {
    public MenuItem(string name, string description, bool vegetarian, double price)
    {
      Name = name;
      Description = description;
      Vegetarian = vegetarian;
      Price = price;
    }

    public override void Print()
    {
      Console.Write("  " + Name);
      if (Vegetarian)
      {
        Console.Write("(v)");
      }
      Console.Write(", " + Price);
      Console.Write("     -- " + Description);
    }

    public override IEnumerator<MenuComponent> GetEnumerator()
    {
      yield break;
    }

    public override void Add(MenuComponent menuComponent)
    {
      throw new NotSupportedException();
    }

    public override void Remove(MenuComponent menuComponent)
    {
      throw new NotSupportedException();
    }

    public override MenuComponent GetChild(int i)
    {
      throw new NotSupportedException();
    }
  }

  /// This is a tree node
  class Menu : MenuComponent
  {
    private List<MenuComponent> MenuComponents;

    public Menu(string name, string description)
    {
      Name = name;
      Description = description;
      MenuComponents = new List<MenuComponent>();
    }

    public override void Add(MenuComponent menuComponent)
    {
      MenuComponents.Add(menuComponent);
    }

    public override void Remove(MenuComponent menuComponent)
    {
      MenuComponents.Remove(menuComponent);
    }

    public override MenuComponent GetChild(int i)
    {
      return MenuComponents[i];
    }

    // we have to use recursion to print all the hierarchy
    public override void Print()
    {
      Console.Write("\n" + Name);
      Console.WriteLine(", " + Description);
      Console.WriteLine("--------------");

      foreach (MenuComponent menuComponent in MenuComponents)
      {
        menuComponent.Print();
        Console.Write("\n");
      }
    }

    public override IEnumerator<MenuComponent> GetEnumerator()
    {
      var components = new Stack<MenuComponent>(new[] { this });
      while (components.Any())
      {
        MenuComponent component = components.Pop();
        yield return component;
        var menu = component as Menu;
        if (menu != null)
        {
          foreach (var n in menu.MenuComponents) components.Push(n);
        }
      }
    }
  }
}

您的代码在任何地方都没有提到IEnumerable—您目前没有尝试实现它。接下来,您没有实现IEnumerator.Current,正如编译器所抱怨的那样……您可能想要的是IEnumerable,而不是IEnumerator?@Groo我只想要任何能工作的东西。我是C的新手,我在这个问题的标题上犯了一个错误,我只想要任何有用的东西。然后,您需要定义在您的案例中实际有效的含义。你想完成什么?你需要用更新的代码编辑问题,以便对其进行评论。请参见“提出一个伟大的问题”。