【问题标题】:How to extracting method's parameter names, and use them as a Dictionary keys?如何提取方法的参数名称,并将它们用作字典键?
【发布时间】:2014-03-24 02:29:56
【问题描述】:

想象一下有这样一个简单的方法:

public async Task<ValidatePhoneNumberResult> ValidatePhoneNumberAsync(
    string phone_number,
    string country_code,
    string country_iso,
    DeviceUuid device_uuid, // DeviceUuid supports his own ToString();
    string os_name,
    string os_version,
    string model,
    string screen_resolution,
    string sim_operator = "00000",
    string is_usim = null
    )
{
    Uri uri = new Uri(MY_URI);
    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);

    Dictionary<string, string> dic = new Dictionary<string, string>();
    dic.Add("phone_number", phone_number.ToString());
    dic.Add("country_code", country_code.ToString());
    dic.Add("country_iso", country_iso.ToString());
    dic.Add("os_name", os_name.ToString());
    dic.Add("model", model.ToString());
    dic.Add("screen_resolution", screen_resolution.ToString());
    dic.Add("sim_operator", sim_operator.ToString());
    if (is_usim != null)
    {
        dic.Add("is_usim", is_usim.ToString());
    }

    request.Content = new FormUrlEncodedContent(dic);
    return await GetResult<ValidatePhoneNumberResult>(request);
}

这是我的第一个设计。从现在开始我会做很多这样的功能。 但是代码有一些我不喜欢的东西。它是向字典添加参数的一部分。我认为这是明显的代码重复。

  • 所有参数名称都用作字典的键。
  • 他们都将实现自己的 ToString() 方法。
  • 如果参数为null,则不应放入字典中。

如果可以的话就更好了:

Dictionary<string, string> dic = new Dictionary<string, string>();
dic.Add("phone_number", phone_number.ToString());
dic.Add("country_code", country_code.ToString());
dic.Add("country_iso", country_iso.ToString());
dic.Add("os_name", os_name.ToString());
dic.Add("model", model.ToString());
dic.Add("screen_resolution", screen_resolution.ToString());
dic.Add("sim_operator", sim_operator.ToString());
if (is_usim != null)
{
    dic.Add("is_usim", is_usim.ToString());
}

// To
var dic = ExtractParametersAndMakeItAsDictionary();

如何使用 C#(5.0) 语法编写此代码?如果您有更好的建议,我将很高兴听到。
如果不可能,是否可以用macro 包裹它?(就像我们写C 时经常做的那样) 告诉我任何可能的删除重复代码的想法:)

【问题讨论】:

标签: c# reflection refactoring c#-5.0 code-duplication


【解决方案1】:

你可以试试这个方法:

public void SomeMethod(string p1, int p2, object p3)
{
    Dictionary<string, string> dic = ExtractParametersAndMakeItAsDictionary(p1, p2, p3);
}

private Dictionary<string, string> ExtractParametersAndMakeItAsDictionary(params object[] parameters)
{
    StackTrace stackTrace = new StackTrace();
    string methodName = stackTrace.GetFrame(1).GetMethod().Name;
    ParameterInfo[] parameterInfos = GetType().GetMethod(methodName).GetParameters();

    return parameters.Where(p => p != null).Zip(parameterInfos, (pv, pi) => new { Name = pi.Name, Value = pv.ToString() }).ToDictionary(x => x.Name, x => x.Value);
}

【讨论】:

    【解决方案2】:

    为什么不改用DTO?这将使序列化变得容易得多。

    public static class Extensions
    {
        public static Dictionary<string, string> ToDicionary(this object o)
        {
            var dic = new Dictionary<string, string>();
            foreach(var property in o.GetType().GetProperties())
            {
                dic.Add(property.Name, string.Format("{0}", property.GetValue(o)));
            }
    
            return dic;
        }
    }
    

    如果你使用对象初始化语法,你甚至不需要改变你调用它的方式:

    public async Task<ValidatePhoneNumberResult> ValidatePhoneNumberAsync(object dto)
    {
        Uri uri = new Uri(MY_URI);
        HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
    
        request.Content = new FormUrlEncodedContent(dto.ToDictionary());
        return await GetResult<ValidatePhoneNumberResult>(request);
    }
    

    你甚至不需要为它创建一个类型:

    var result = await ValidatePhoneNumberAsync(
        new
        {
                phone_number = "000000000",
                country_code = "code",
                country_iso = "iso",
                device_uuid = new DeviceUuid(),
                os_name = "Windows",
                os_version = "6.3",
                model = "model",
                screen_resolution = "4K",
                sim_operator = "00000",
                is_usim = null
        });
    

    【讨论】:

    • object 方法的问题在于它不是类型安全的。如果您忘记指定参数之一,或错误输入其名称,则不会出现编译错误。
    猜你喜欢
    • 1970-01-01
    • 2021-12-10
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 2019-07-14
    • 2021-12-24
    • 1970-01-01
    相关资源
    最近更新 更多