#c# #jquery
#c# #jquery ( jquery )
Вопрос:
Я не знаю, как правильно назвать этот вопрос, поэтому не мог его изменить. Мой вопрос в том, что у меня есть около 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);
}
Методы очень похожи, но они возвращают разные поля. Я подумываю о рефакторинге всех методов в один, получая поля для возврата в качестве параметров. Хорошая ли это идея? Как я могу это сделать? Отражение?
Комментарии:
1. Можете ли вы отредактировать свой вопрос, включив в него 2-й аналогичный метод, чтобы мы могли видеть, что между ними одинаковое / разное.
Ответ №1:
Прежде всего, вам нужно знать, что объект и словарь представлены в 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;}
}
Комментарии:
1. @сам, это самое дешевое решение, потому что нет отражения.
2. Также сериализация словаря должна быть дешевой, чем сериализация анонимного объекта, потому что, когда сериализатор выполняет сериализацию объекта, он использует отражение.
3. хаззик, а как насчет проблемы безопасности, на которую указал Майк? (если его не просят слишком много рупий)
4. @myself в моем примере вы контролируете, какие данные должны быть отправлены.
Ответ №2:
Я не думаю, что это ужасная идея, особенно если у вас есть тонны этих методов и вы хотите упростить свой API.
Несколько недостатков:
1) Отражение требует дополнительных затрат. Вероятно, это не имеет большого значения, если вы не размером с Twitter.
2) Потенциально могут возникнуть проблемы с безопасностью, если у данных есть какие-либо свойства, к которым вы НЕ хотите, чтобы пользователи получали доступ, например, какие-то внутренние ключи базы данных или что-то еще. Убедитесь, что каждое свойство вашего класса является тем, которое вы полностью согласны сделать общедоступной информацией.
Комментарии:
1. Да, я думаю, вы правы, стоимость производительности и безопасность каждого свойства (со вторым я могу обойти, создав пользовательский атрибут и добавив его в определенные поля, если его еще нет, чтобы предотвратить чтение свойств отражением).
2. Поможет ли кэширование
PropertyInfo
объектов повышению производительности в .NET? Вместо того чтобы использовать любую строку в качестве ключа поля, вы могли бы превратить строку в индекс в словарь «разрешенных»PropertyInfo
дескрипторов, что помогло бы как с производительностью, так и с безопасностью.
Ответ №3:
Вы можете использовать лямбда-выражение для рефакторинга, устраняющего дублирование: . Это сведет все ваши методы к одной строке кода:
[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);
}
Ответ №4:
Другой подход заключается в использовании 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;}
}