将多个方法重构为一个方法
本文关键字:方法 一个 重构 | 更新日期: 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;}
}