简体   繁体   中英

Get the names of parameters method

I have a method with a ton of parameters. Some of them are optional. So, in order to use this method easily I use the optional parameter feature.

Moreover, this method builds a Dictionary<string,string> with name of parameter as key of the dictionary and value of the parameter as value of the dictionary for non-null parameters only.

Here is the method :

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;
}

Can be called with named parameters as:

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

As you can see, the method is a little bit verbose. I want to know if there is a more concise way to write it (without reflection)

Thank you !

EDIT

Thank you for your answers However, I'm not clear in my question. Just a precision :

  • parameter names in my real method are not param1, param2 etc. but more business name like id, firstName, lastName, address1 = null. Like this when we use this method, it's more easy to know which parameter is mandatory or not. Before this I used params string[] but when I used it i can't have the name of the parameter.

Hope my explanation is more clear now.

Well, a method with that many parameters is for sure a code smell. I would consider to create a support class, to be used as a DTO (Data Transfer Object).

Something simple like:

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);
    }
}

The code is slightly repetitive, but is as simple as it can be, and good enough for my tastes.

If you can trade ease of maintenance with performance, you can leverage the dynamic serialization capabilities of the vast majority of Json libraries.

Using Json.Net , you could do something like:

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);
}    

It will not be as fast as it can, but as long as you are treating simple types, it will perform just fine and adapt to every parameter you can throw into the list.

This approach has the great advantage of being really simple to debug and manage: no positional parameter is needed.

Edit: I missed the "exclude not null values" requirement. I edited the code to support that.

Refactor the method to the following and use code contracts to check the params length. In that way you will have compile time errors if you try to use it with less than 5 parameters.

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

    }

In future, if you have that many parameters:

  • Use an array, or
  • Put them in a struct or class instead.

In this case, you can use an array:

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

Please consider using param keyword instead. Have a look at this example to know the usage of params keyword. It will help you passing variable number of arguments to a method. After the changes your method signature would look something like this:

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
    }

I suggest using params instead of list of parameters:

// 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);
}

Test:

  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);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM