【问题标题】:How to pass an arbitrary number of parameters in C#如何在 C# 中传递任意数量的参数
【发布时间】:2009-01-28 20:56:10
【问题描述】:

好的,我需要设计一种方法来跟踪每个项目的存在数量。 大约有 26 个项目。我还需要一种方法来确定是否存在某种项目组合。

例如, 这是纸牌游戏的引擎。每张卡片都有不同的类型,每张卡片都可以附有卡片。 为了让玩家在游戏中做某些事情,需要有一定的卡片组合附加到一张卡片上。 为了简化这个程序,我想做类似的事情

if (meetsCrit(2, water, 4, ground))
{
    do this()
}
else
{
    displayerror()
}

编辑:已解决!

我使用了下面几篇文章中描述的技术组合。 特别提及:

乔恩·斯基特, 里纳特·阿卜杜林, 弗兰克,

无论如何,这就是我所做的 我创建了一个名为 pair 的类,它存储我要查找的类型以及该类型的数量。 然后我使用了一个谓词代表来查找所有该类型并计算有多少, 然后我将它与我正在搜索的数字进行比较,并分别返回 true 或 false。

这是它的代码

public bool meetsCrit(params Pair[] specs)
{
    foreach (Pair i in specs)
    {
        if (!(attached.FindAll(delegate(Card c) { return c.type == i.type; }).Count >= i.value))
        {
            return false;
        }

    }
    return true;
}

【问题讨论】:

  • Michael:你需要比这更具体——它非常模糊。否则你只会被否决而被遗忘。
  • 这个问题的措辞非常混乱。
  • 你如何告诉你的代码什么是“气球”和什么是“纸杯蛋糕”?
  • 每个人都知道气球会漂浮,而纸杯蛋糕就是你吃的东西。
  • 您介意使用其他集合类型吗?字典等也可以帮助解决这个问题。

标签: c# arrays parameters


【解决方案1】:

使用params:

params 关键字可让您指定一个method parameter,该method parameter 接受一个参数,其中参数的数量是可变的。

方法声明中的params关键字后面不允许有附加参数,方法声明中只允许有一个params关键字...

【讨论】:

  • params 强制用户使用数组。他的帖子是在问他是否可以在不使用数组的情况下做到这一点。
  • 不,params 允许您继续向调用添加参数,它不需要您使用数组。
  • 该方法需要是 Method(params T[] arr) 声明,但该方法的调用者不需要创建数组。调用者可以做 Method(t1, t2)
  • 调用者不会显式创建数组,但我认为可以公平地说调用仍在使用数组。
  • -1 你为什么不至少尝试自己回答这个问题,而不是提供一个明天可能会死也可能不会死的链接?
【解决方案2】:

使用 params 关键字传递可变数量的参数:

   private static void HowMayItems<T>(params T[] values) {
        foreach (T val in values) { 
            //Query how many items here..
        }
    }

您还可以创建一个谓词并将其传递给参数过滤器。在该方法中,您可以返回所有结果的并集。是这样的:

public class Item { 
    public string Name { get; set; }
}
public class ItemFilter {
    public string Name { get; set; }
    public ItemFilter(string name) {
        Name = name;
    }
    public bool FilterByName(Item i) {
        return i.Name.Equals(Name);
    }
}

public class ItemsTest {
    private static List<Item> HowMayItems(List<Item> l,params ItemFilter[] values)
    {
        List<Item> results= new List<Item>();
        foreach(ItemFilter f in values){
            Predicate<Item> p = new Predicate<Item>(f.FilterByName);
            List<Item> subList = l.FindAll(p);
            results.Concat(subList);
        }
        return results;
    }
}

编辑:

好的,我的混合坚果版本怎么样 :):

public enum ItemTypes{
    Balloon,
    Cupcake,
    WaterMelon
    //Add the rest of the 26 items here...
}

public class ItemFilter {
    private ItemTypes Type { get; set; }
    public ItemFilter(ItemTypes type) {
        Type = type;
    }
    public bool FilterByType(ItemTypes type) {
        return this.Type == type;
    }
}

public class PicnicTable {
    private List<ItemTypes> Items;

    public PicnicTable() {
        Items = new List<ItemTypes>();
    }

    public void AddItem(ItemTypes item) {
        Items.Add(item);
    }

    public int HowMayItems(ItemTypes item)
    {
        ItemFilter filter = new ItemFilter(item);
        Predicate<ItemTypes> p = new Predicate<ItemTypes>(filter.FilterByType);
        List<ItemTypes> result = Items.FindAll(p);
        return result.Count;
    }
}

public class ItemsTest {
    public static void main(string[] args) {
        PicnicTable table = new PicnicTable();
        table.AddItem(ItemTypes.Balloon);
        table.AddItem(ItemTypes.Cupcake);
        table.AddItem(ItemTypes.Balloon);
        table.AddItem(ItemTypes.WaterMelon);
        Console.Out.WriteLine("How Many Cupcakes?: {0}", table.HowMayItems(ItemTypes.Cupcake));
    }
}

【讨论】:

    【解决方案3】:

    参数数组是显而易见的答案。另一种方法是创建一个类来表示标准。然后您可以使用集合初始化器,例如:

    bool result = myCollection.Contains(new Criteria {
                     { 2, Item.Balloon },
                     { 4, Item.Cupcake }
                  });
    

    但如果这也没有用,我们肯定需要在问题中提供更多信息。

    如果您可以提供一个示例,说明您喜欢调用该方法时使用的语法,那肯定会对我们有所帮助。

    【讨论】:

      【解决方案4】:

      params 关键字允许您以非数组形式传递任意数量的参数。但是,它们将被转换为函数内部的数组。我不知道任何编程结构会不同于任何语言。

      【讨论】:

        【解决方案5】:

        好的,因为我喜欢它,一些代码可以计算出您在某个列表中有多少个任意数量的类型的实例...

        我需要有趣的计数器:

          public class FunnyCounter
          {
            Dictionary<Type, int> restrictions = new Dictionary<Type, int>();
            public FunnyCounter Add<T>(int appears)
            {
              restrictions.Add(typeof(T), appears);
              return this;
            }
        
            public void PassThrough(object o)
            {
              if (restrictions.ContainsKey(o.GetType()))
                restrictions[o.GetType()] = restrictions[o.GetType()] - 1;
            }
        
            public bool SatisfiedAll()
            {
              return restrictions.Values.Aggregate(true, (b, i) => b && i == 0);
            }
        

        现在有一个类似的列表

        List<Stuff> l = new List<Stuff> { new Ball(), new Ball(), new Bucket() };
        

        我愿意……

        FunnyCounter counter = new FunnyCounter();
        counter.Add<Ball>(2).Add<Bucket>(1);
        l.ForEach(counter.PassThrough);
        Console.WriteLine(counter.SatisfiedAll());
        

        【讨论】:

          【解决方案6】:

          以下是我将如何以简化的方式完成此操作:

          var collection = new[] {Item.Baloon, Item.Cupcake, Item.Baloon, Item.Coke};
          
          var result = collection.Contains(2.Baloons(), 1.Cupcakes());
          

          地点:

          public enum Item
          {
              Baloon,
              Cupcake,
              Coke
          }
          
          public static class TableExtensions
          {
              public static Pair<Item, int> Baloons(this int count)
              {
                  return Tuple.From(Item.Baloon, count);
              }
          
              public static Pair<Item, int> Cupcakes(this int count)
              {
                  return Tuple.From(Item.Cupcake, count);
              }
          
              public static bool Contains(this IEnumerable<Item> self, 
                  params Pair<Item, int>[] criteria)
              {
                  foreach (var pair in criteria)
                  {
                      var search = pair.Key;
                      if (self.Count(item => item == search) < pair.Value)
                          return false;
                  }
                  return true;
              }
          }
          

          备注:

          • 您不关心参数中项目的顺序。
          • 我使用枚举来表示对象,但这些也可以是对象
          • 元组来自Lokad.Shared
          • 目前包含“至少 X 项”的搜索。通过传递实际上是可枚举 - 规则的谓词的标准对象,我们可以拥有更大的灵活性。这将保持语法相同,但允许有更多选项(即:AtLeastAtMost、X.VegetarianSets、Y.饮料等)。如果有兴趣,请查看validation and business rules application block 中的预定义验证规则,了解类似的规则组合方法。

          【讨论】:

            【解决方案7】:

            我会采用一个谓词,该谓词可以根据您的数据源进行评估,然后对其进行评估,从谓词返回结果。

            【讨论】:

              【解决方案8】:

              除了使用 params 关键字,它会强制您将项目添加到数组中,C# 目前不支持此功能。 C# 4.0 将在语言中引入可选参数,但我不确定这对你是否足够任意

              【讨论】:

              • 不,params 允许你在调用中不断添加参数,它不需要你使用数组。
              • 请问……方法中的数据类型是什么样的?不是数组吗?
              • +1 给 David 的 cmets。如果你试图声明一个 params 参数而不是一个数组类型,你会得到:错误 CS0225: The params parameter must be a 一维数组
              • msdn.microsoft.com/en-us/library/aa645765(VS.71).aspx“参数数组”,由 C# 语言规范提供。
              • 这取决于你如何分割 OP 问题。他问你如何在不使用数组的情况下传递任意数量的变量给方法。所以调用者不必使用带有 params 关键字的数组。所以斯瓦格纳是对的。实现必须使用数组,所以 David 也是正确的。
              【解决方案9】:

              这些项目是如何存储的?它们应该存储在项目集合对象中。它应该有必要的方法来检查它的内脏。

              或者使用实现 IItem 接口的对象的 params 数组。

              【讨论】:

                【解决方案10】:
                bool doTheseItemsExist(List criteria) { .. }
                

                你不能简单地传入一个对象列表吗?从技术上讲,它类似于传递一个数组,但它很容易使用,并且如果您使用 params,您不必使用可能很大的参数列表加载调用堆栈。 (当然,最后一部分完全取决于您打算搜索多少个条件。)

                (编辑:实际上,该 List 需要是对象类型和预期数量的映射。)

                但是建议您的集合应该在您的集合中公开这些查询的先生们可能是这里的赢家。一种可能:

                bool MyCollection.HasBalloons(int numBalloons);
                bool MyCollection.HasCupcakes(int numCupcakes);
                bool MyCollection.HasPartyHats(int numHats);
                

                但是 bool 结果对调用者来说是模棱两可的......有这么多吗?至少有这么多?所以也许更好的方向是:

                int MyCollection.NumBalloons();
                int MyCollection.NumCupcakes();
                int MyCollection.NumPartyHats();
                

                然后您就不需要带有任意参数集的额外功能。您可以根据需要简单地检查集合。

                【讨论】:

                  【解决方案11】:

                  数组可能会完成这项工作,但它并不完全优雅。 你有一个包含不同类型项目的集合的类吗? 另一个更精确的解决方案是使用字典

                  Dictionary<String, int> numberOfEach = new Dictionary<string, int>();
                  numberOfEach.Add("balloons", 2);
                  numberOfEach.Add("cupcakes", 4);
                  

                  然后你的类中就会有一个方法(带有集合的方法)

                  public bool correctAmmounts(Dictionary<String, int> numberOfEach)
                  {
                      return collection1.Count == numberOfEach["balloons"] &&
                             collection2.Count == numberOfEach["cupcakes"];
                  }
                  

                  其中 collection1 有一些气球,而 collection2 有一些纸杯蛋糕。

                  但是,如果不同类型的数量发生变化,您将不得不编辑您的方法。

                  【讨论】:

                    【解决方案12】:

                    我想知道这个问题是否有些问题。 如果您询问某个对象是否包含 n 个这个和 y 个那个,那么您的对象可以被枚举。在这种情况下,它应该实现 IEnumerable ,其中 T 将是“您的内容的共同点”。 从这里开始,您可以使用例如LINQ 以获取您问题的答案或将此类问题封装到对象中并提供例如Jon 所展示的标准系统...

                    【讨论】:

                      【解决方案13】:

                      这听起来像是做一些 OOP 的好机会:

                      假设你有一些代表你的物品的类

                      public class Item
                      {
                        public string Name{ get; set; }
                        // Here put all the properties that are common to all items.
                      }
                      
                      public class Cupcake : Item
                      {
                        // By inheriting from Item, it will have Name 
                        //  along with anything else you define there
                      
                        public bool HasFrosting{ get; set; }
                        // Put whatever else Cupcake needs here
                      }
                      
                      public class Baloon : Item
                      {
                        public Color MyColor{ get; set; }
                      }
                      

                      然后在你的应用程序代码中

                      // From your post, I can't tell where you're getting
                      //  your items, so I'll just put a placeholder here for now.
                      //  I assume this returns all kinds of items:
                      //  Cupcakes, Baloons, and other fun stuff
                      Item[] items = GetItemsFromSomewhere();
                      
                      int cupcakeCount = GetCupcakeCount(items);
                      
                      ...
                      
                      public int GetCupcakeCount( Item[] items )
                      {
                        int cupcakeCount = 0;
                      
                        // This is the code for checking types of items
                        //  you could use a LINQ statement or whatever you like
                        //  but i just put a foreach loop here for simplicity
                        foreach( Item item in items )
                        {
                          // Check the types of each object, 
                          if(item is Cupcake)
                           ++cupcakeCount;
                        }
                      
                        return cupcakeCount;
                      }
                      

                      即使您可以通过其他方式做到这一点,也请考虑 OOP,因为您似乎需要区分对象类型并进行比较。这可能是准确表示您的系统的好方法。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 2020-11-10
                        • 1970-01-01
                        • 2022-06-27
                        • 2020-03-03
                        • 2022-11-10
                        • 2017-12-18
                        • 1970-01-01
                        相关资源
                        最近更新 更多