将多个方法重构为一个方法

本文关键字:方法 一个 重构 | 更新日期: 2023-09-27 18:12:40

我不知道如何正确命名这个问题,所以请随意更改它。我的问题是,我有大约10个方法,看起来像:

[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
    EUser user = (EUser)Session["user"];
    var json = new { result = true, user.Image, user.Biography };
    return new JavaScriptSerializer().Serialize(json);
}

[WebMethod(EnableSession = true)]
public string ReadUserBasicInformation()
{
    EUser user = (EUser)Session["user"];
    var json = new { result = true, user.Name, user.Username};
    return new JavaScriptSerializer().Serialize(json);
}

方法非常相似,但是它们返回不同的字段。我正在考虑将所有方法重构为一个,接收作为参数返回的字段。这是个好主意吗?我该怎么做呢?反射?

将多个方法重构为一个方法

首先你需要知道对象和字典在json中的呈现方式是相似的。

[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
    return GetUserInfo(new [] 
    {
        new FieldInfo {Name = "Image", u => u.Image},
        new FieldInfo {Name = "Biography", u => u.Biography} 
    });
}
private string GetUserInfo(FieldInfo[] infos) 
{
    EUser user = (EUser)Session["user"];
    var dict = new Dictionary<string, object>{ { "result", true } };
    foreach(var info in infos) 
    {
        dictionary.Add(info.Name, info.Accessor(user));
    }
    return new JavaScriptSerializer().Serialize(dict );
}
public class FieldInfo 
{
    public Func<EUser, object> Accessor { get; set; }
    public string Name { get; set;}
}

我不认为这是一个糟糕的主意,特别是如果你有大量这样的方法,并希望简化你的API。

几个缺点:

1)反射是有代价的。这可能无关紧要,除非你是Twitter的大小。

2)如果数据有任何你不希望用户访问的属性,比如某种内部数据库键或其他什么,可能会有潜在的安全问题。确保你的类中的每个属性都是你完全可以成为公共信息的。

你可以使用lambda来重构掉重复:这将把你所有的方法减少到一行代码:

[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
    return GetUserJSON(x => new { result = true, x.Image, x.Biography });
}
[WebMethod(EnableSession = true]
public string ReadUserBasicInformation()
{
    return GetUserJSON(x => new { result = true, x.Name, x.UserName });
}
private string GetUserJSON(Func<EUser, string> jsonFields)
{
    EUser user = (EUser)Session["user"];
    var json = jsonFields(user);
    return new JavaScriptSerializer().Serialize(json);
}

另一种方法是使用Automapper或类似的库来投影数据。

[WebMethod(EnableSession = true)]
public string ReadUserAdditional()
{
    return GetUserInfo<UserAdditionalDto>();
}
private string GetUserInfo<TDto>(FieldInfo[] infos) 
{
    EUser user = (EUser)Session["user"];
    var dto = Mapper.Map<TDto>(user); // Mapper is Automapper entry class.
    return new JavaScriptSerializer().Serialize(dto );
}
public class UserAdditionalDto
{
    public string Image { get; set; }
    public string Biography { get; set;}
}