Как эффективно использовать DTO на основе сценария в C#
Я работаю над моделью сотрудника, она содержит всю информацию о сотруднике
Например:
public class Employee
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string HomePhone { get; set; }
public string MobilePhone { get; set; }
}
У меня есть два метода для получения записей сотрудника
public Employee GetEmployeeName(int id)
{
// The return should contain only FirstName, MiddleName and LastName.
// The rest of the properties should be non-accessable (i.e., Private)
}
public Employee GetEmployeeContacts(int id)
{
// The return should contain only EmailAddress, HomePhone and MobilePhone.
// The rest of the properties should be non-accessable (i.e., Private)
}
public Employee GetEmployeeNameEmail(int id)
{
// The return should contain only FirstName, MiddleName, LastName and EmailAddress.
// The rest of the properties should be non-accessable (i.e., Private)
}
public Employee GetEmployee(int id)
{
// It should return the entire Employee object
}
Как я мог этого добиться? Не могли бы вы, пожалуйста, любую помощь в этом отношении.
2 ответа
Простой ответ заключается в том, что вы не можете изменить видимость свойств объекта от одного экземпляра к другому - это то, что определяет класс. Вы можете сделать одно из следующего:
Используйте динамический объект, который имеет множество плюсов и минусов. Смотрите здесь и здесь.
Используйте наследование для определения базового класса (например,
EmployeeCommon
) с общими свойствами знаменателя и подклассами для каждого дополнительного подмножества (EmployeeCommonAndPhoneNumbers
) вы хотите вернуться от ваших различных методов.Разделите различные наборы свойств на отдельные классы "группы свойств" (например,
ContactInfo
) и поместите их как свойства на вашEmployee
учебный класс. Индивидуальные свойства (какFirstName
или жеEmailAddress
) то, что вы хотите "показать и скрыть", может присутствовать или отсутствовать в каждом экземпляре Employee по мере необходимости, но все различные объекты "группы свойств" все равно будут присутствовать в каждом экземпляреEmployee
как собственность (хотя они будутnull
в случаях, когда они не нужны), так что это может или не может соответствовать вашим требованиям.
В сводке вашего вопроса упоминалось, что вы намерены создать DTO, то есть объекты передачи данных, предположительно в контексте обмена сообщениями API. Ваш класс Employee, безусловно, может служить этой цели и может также выступать в качестве класса бизнес-объекта со своей собственной бизнес-логикой, помимо только перечисленных вами автоматических свойств.
IIUC, специализированная GetEmployee...
методы будут жить в отдельном фабричном классе и будут создавать экземпляры Employee
с заполнением только обязательных свойств. Я предполагаю, что вы хотите сделать это, потому что ваш API включает в себя разные контракты сообщений с различными подмножествами свойств Employee. GetEmployeeNameEmail
Реализация метода будет искать Employee с указанным идентификатором, создавать новый экземпляр Employee, заполнять только свойства name и email и возвращать этот объект.
Вы не можете сделать методы приватными для этих различных контекстов DTO; но вы можете "спрятать" их, определив отдельные интерфейсы для каждого подмножества свойств. Подкласс Employee будет реализовывать каждый из этих интерфейсов:
public interface IEmployeeWithName
{
int EmployeeId { get; set; }
string FirstName { get; set; }
string MiddleName { get; set; }
string LastName { get; set; }
}
interface IEmployeeWithContacts
{
int EmployeeId { get; set; }
string EmailAddress { get; set; }
string HomePhone { get; set; }
string MobilePhone { get; set; }
}
interface IEmployeeWithNameEmail
{
int EmployeeId { get; set; }
string FirstName { get; set; }
string MiddleName { get; set; }
string LastName { get; set; }
string EmailAddress { get; set; }
}
interface IEmployee
{
int EmployeeId { get; set; }
string FirstName { get; set; }
string MiddleName { get; set; }
string LastName { get; set; }
string EmailAddress { get; set; }
string HomePhone { get; set; }
string MobilePhone { get; set; }
}
public class Employee : IEmployee, IEmployeeWithContacts, IEmployeeWithName, IEmployeeWithNameEmail
{
public int EmployeeId { get; set; }
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string HomePhone { get; set; }
public string MobilePhone { get; set; }
}
public class EmployeeFactory
{
private Employee GetEmployeeByID(int id)
{
// this would perform the lookup and populate the Employee object...
return new Employee();
}
public IEmployeeWithName GetEmployeeName(int id)
{
// The return should contain only FirstName, MiddleName and LastName.
return GetEmployeeByID(id);
}
public IEmployeeWithContacts GetEmployeeContacts(int id)
{
// The return should contain only EmailAddress, HomePhone and MobilePhone.
return GetEmployeeByID(id);
}
public IEmployeeWithNameEmail GetEmployeeNameEmail(int id)
{
// The return should contain only FirstName, MiddleName, LastName and EmailAddress.
return GetEmployeeByID(id);
}
public IEmployee GetEmployee(int id)
{
// It should return the entire Employee object
return GetEmployeeByID(id);
}
}
Обратите внимание, что если вы передадите их отражающему сериализатору, вашего фасада интерфейса может оказаться недостаточно, чтобы скрыть свойства, которые вы хотите подавить. В этом случае вам придется вернуться к созданию нового объекта Employee, но вы можете использовать что-то вроде AutoMapper в сочетании со специализированными интерфейсами для уменьшения избыточности кода.