【问题标题】:Get the names of parameters method获取参数方法的名称
【发布时间】:2016-10-21 10:31:37
【问题描述】:

我有一个带有大量参数的方法。其中一些是可选的。所以,为了方便使用这个方法,我使用了可选参数功能。

此外,此方法仅针对非空参数构建一个Dictionary<string,string>,其中参数名称作为字典的键,参数的值作为字典的值。

方法如下:

public string CreateParameterDictionary(
    string id,
    string firstName,
    string lastName,
    string address,
    string postalCode,
    string lorem = null,
    string ipsum = null,
    string dolor = null,
    //...
    string sit = null,
    string amet = null)
{
    if (String.IsNullOrWhiteSpace(id) ||
        String.IsNullOrWhiteSpace(firstName) ||
        String.IsNullOrWhiteSpace(lastName) ||
        String.IsNullOrWhiteSpace(address) ||
        String.IsNullOrWhiteSpace(postalCode))
    {
        throw new ArgumentNullException($"nameof((id) nameof(firstName) nameof(lastName) nameof(address) nameof(postalCode)");
    }

    Dictionary<string,string> parametersDictionary = new Dictionary<string, string>();
    parametersDictionary.Add(nameof(((id),((id);
    parametersDictionary.Add(nameof(firstName),firstName);
    parametersDictionary.Add(nameof(lastName),lastName);
    parametersDictionary.Add(nameof(address),address);
    parametersDictionary.Add(nameof(postalCode),postalCode);

    if (!String.IsNullOrWhiteSpace(lorem)) parametersDictionary.Add(nameof(lorem), lorem);
    if (!String.IsNullOrWhiteSpace(ipsum)) parametersDictionary.Add(nameof(ipsum), ipsum);
    if (!String.IsNullOrWhiteSpace(dolor)) parametersDictionary.Add(nameof(dolor), dolor);
    //...
    if (!String.IsNullOrWhiteSpace(sit)) parametersDictionary.Add(nameof(sit), sit);
    if (!String.IsNullOrWhiteSpace(amet)) parametersDictionary.Add(nameof(amet), amet);

    return parametersDictionary;
}

可以使用命名参数调用:

CreateParameterDictionary(5, "Dexter, "Morgan", "Miami", 12345, dolor: 5);

如您所见,该方法有点冗长。想知道有没有更简洁的写法(不用反思)

谢谢!

编辑

感谢您的回答但是,我的问题并不清楚。只是一个精度:

  • 我的真实方法中的参数名称不是param1,param2等,而是更多的业务名称,如id,firstName,lastName,address1 = null。 像这样,当我们使用这种方法时,更容易知道哪个参数是强制性的或不是强制性的。在此之前,我使用了 params string[],但是当我使用它时,我无法获得参数的名称。

希望我的解释现在更清楚了。

【问题讨论】:

  • 您可能希望将我给 Radin 的示例合并到我的一个 cmets 中 - CreateParameterDictionary("a","b","c","d","e",param16:"p"); - 很明显可选参数不会“用完”或在声明顺序中指定,并且这就是为什么params 解决方案都是错误的,如果这是你的意图的话。 (当然,在您的问题中,您可以进一步充实示例。我需要一些内容以适合评论)

标签: c# optional-parameters nameof


【解决方案1】:

嗯,有这么多参数的方法肯定是代码异味。 我会考虑创建一个支持类,用作 DTO(数据传输对象)。

简单的:

public class YourBusinessObjectRequestDto
{
    public string id { get; set; }
    public string firstName { get; set; }
    public string lastName { get; set; }
    public string address { get; set; }
    public string postalCode { get; set; }
    ...

    public Dictionary<string, string> ToDictionary()
    {
        var dict = new Dictionary<string, string>()
        {
          { "id", id },
          { "firstName", firstName },
          { "lastName", lastName },
          { "address", address },
          { "postalCode", postalCode },
          { "...", ... }
        };

        return dict.Where(pair => pair.Value != null).ToDictionary(pair => pair.Key, pair => pair.Value);
    }
}

代码略有重复,但尽可能简单,并且足以满足我的口味。

如果您可以用易于维护来换取性能,那么您可以利用绝大多数 Json 库的动态序列化功能。

使用Json.Net,您可以执行以下操作:

public Dictionary<string, string> ToDictionary()
{
    var json = JsonConvert.SerializeObject(this);

    var serializerSettings = new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore };

    return JsonConvert.DeserializeObject<Dictionary<string, string>>(json, serializerSettings);
}    

它不会尽可能快,但只要您处理简单类型,它就会执行得很好并适应您可以放入列表中的每个参数。

这种方法具有调试和管理非常简单的巨大优势:不需要位置参数。

编辑: 我错过了“排除非空值”的要求。我编辑了代码来支持它。

【讨论】:

    【解决方案2】:

    我建议使用params 而不是参数列表:

    // you want to return Dictionary<String, String>  - right?
    // static - I can't see any use of "this" in the method
    public static Dictionary<string, string> CreateParameterDictionary(
      params String[] values) {
    
      if (null == values)
        throw new ArgumentNullException("values");
    
      // Required: we want at least 5 parameters
      if (values.Length < 5)
        throw new ArgumentException("Too few parameters");
    
      // First 5 parameters must not be null or empty
      if (values.Take(5).Any(item => String.IsNullOrEmpty(item)))
        throw new ArgumentException("First five parameters must not be null or empty");
    
      return values
        .Select((item, index) => new {
          index = index + 1,
          value = item
        })
        .Where(item => !String.IsNullOrWhiteSpace(item.value))
        .ToDictionary(item => "param" + item.index.ToString(),
                      item => item.value);
    }
    

    测试:

      var result = CreateParameterDictionary("A", "B", "C", "D", "E", "F");
    
      String report = String.Join(Environment.NewLine, 
        result.Select(pair => String.Format("{0} = {1}", pair.Key, pair.Value)));
    
      // param1 = A
      // param2 = B
      // param3 = C
      // param4 = D
      // param5 = E
      // param6 = F
      Console.Write(report);
    

    【讨论】:

      【解决方案3】:

      将方法重构为以下内容并使用代码协定检查参数长度。这样一来,如果您尝试使用少于 5 个参数的参数,就会出现编译时错误。

       public string CreateParameterDictionary(
            string param1,
            string param2,
            string param3,
            string param4,
            string param5,
            params string[] optionalParametes)
          {
            Contract.Requires(optionalParametes.Length <= 24);
      
          }
      

      【讨论】:

      • 但是现在您已经丢失了 name->value 映射,因为不清楚数组中的第一个成员是作为 param6 还是作为 param16 传递的。并且参数的名称当前用作字典中的键。
      • @Damien_The_Unbeliever,你没有失去它。使用参数,您将通过它们在数组中的位置来访问这些值。所以第 6 个参数放在第一位,第 7 个放在第二位,依此类推。这与可选参数相同,因为您不能跳过前 10 个并仅为 param16 设置值,您需要在两种情况下填写所有先前的参数.
      • 完全可以将 OPs 现有方法称为CreateParameterDictionary("a","b","c","d","e",param16:"p");。您是否错过了named and optional parameters 上的备忘录?
      • @Damien_The_Unbeliever,你是对的,我忘了这个:)
      【解决方案4】:

      请考虑改用 param 关键字。查看this 示例以了解 params 关键字的用法。它将帮助您将可变数量的参数传递给方法。更改后,您的方法签名将如下所示:

      public string CreateParameterDictionary(
              string param1,
              string param2,
              string param3,
              string param4,
              string param5,
              param string[] variableParams = null,
             )
          {
                //variableParams will contain your parameters from param6 to param30
          }
      

      【讨论】:

        【解决方案5】:

        将来,如果你有那么多参数:

        • 使用数组,或
        • 改为将它们放在结构或类中。

        在这种情况下,您可以使用数组:

        public string CreateParameterDictionary(string[] param)
        {
            ... same as before, but using param[4] instead of param4, etc...
        }
        

        【讨论】:

        • 甚至params string[] param
        • 是的,我感觉提问者心里有这样的答案。
        猜你喜欢
        • 2015-10-01
        • 2011-10-09
        • 2010-09-18
        • 2010-09-17
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多