Я знаю, что это только позволяет классу устанавливать его, но какой смысл?
Как я решаю проблему наличия идентификаторов только для чтения?
Скажите, что у меня есть класс человека:
public class Person
{
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
И это находится в Entities.dll
, используемый GUI, BL и DAL.
GUI называет BL:
List<Person> p = BL.PeopleBL.GetPeople();
Ради примера называет DAL:
...
while(dr.read())
{
returnPersonList.add( new Person{ Age=dr.GetInt32(1), Id=dr.GetInt32(0), Name=dr.GetString(2)})
}
...
конечно, я не могу сделать, тот идентификатор причины является частным набором; Что надлежащий путь состоит в том, чтобы сделать это?
Как я могу позволить BL/Dal установить идентификатор, но не на GUI?
Или это даже не надлежащее использование частного набора?
Я просто хотел добавить, что это - Ваше типичное приложение DB, где pk является идентификатором и не должен быть изменен (только BL/DAL)
Вот одно из возможных решений, хотя и не очень чистое:
internal
BAL.dll
& DAL. dll
Internal Visible в assemblyinfo.cs
public class Person
{
public Person(int id)
{
this.Id=id;
}
public string Name { get; set; }
public int Id { get; internal set; }
public int Age { get; set; }
}
AssemblyInfo.cs
для Entities.dll
[assembly: InternalsVisibleTo("DAL"), InternalsVisibleTo("BAL")]
Таким образом, все ваши внутренние компоненты будут видны DAL и BAL. Это может быть нежелательно, но я просто предлагаю одно из возможных решений.
Два общих подхода: либо класс должен иметь конструктор для использования DAL, либо DAL должен использовать отражение для гидратации объектов.
Или вы можете сделать
public class Person
{
public Person(int id)
{
this.Id=id;
}
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
Возможно, я неправильно понимаю, но если вы хотите действительно readonly Ids, почему бы не использовать фактическое readonly поле?
public class Person
{
public Person(int id)
{
m_id = id;
}
readonly int m_id;
public int Id { get { return m_id; } }
}
Вы можете позволить пользователю установить свойство только для чтения, предоставив его через конструктор:
public class Person
{
public Person(int id)
{
this.Id = id;
}
public string Name { get; set; }
public int Id { get; private set; }
public int Age { get; set; }
}
Возможно, вы можете пометить их как внутренние, и в этом случае только классы в вашем DAL или BL (если они являются отдельными dll) смогут их установить.
Вы также можете предоставить конструктор, который принимает поля и затем раскрывает их только как свойства.
while(dr.read())
{
returnPersonList.add(
new Person(dr.GetInt32(1), dr.GetInt32(0), dr.GetString(2)));
}
где:
public class Person
{
public Person(int age, int id, string name)
{
Age = age;
Id = id;
Name = name;
}
}
Обычно это так, когда идентификатор не является естественной частью объекта, а является артефактом базы данных, который необходимо абстрагировать.
Это дизайнерское решение - разрешить установку идентификатора только во время построения или при вызове метода, поэтому класс управляется внутренне.
Вы можете написать установщик самостоятельно, предполагая, что у вас есть резервное поле:
private int Id = 0;
public void SetId (int id)
{
this.Id = id;
}
Или через конструктор:
private int Id = 0;
public Person (int id)
{
this.Id = id;
}
В зависимости от сферы применения, мне нравится размещать механизмы увлажнения объекта в самом объекте. Я оберну читателя данных пользовательским объектом и передам ему делегат, который будет выполнен после возврата запроса. Делегату передается DataReader. Затем, поскольку я нахожусь в своем интеллектуальном бизнес-объекте, я могу выполнять гидратацию с помощью своих частных сеттеров.
Обертка "DataAccessWrapper" обертывает для меня все управление соединением и жизненным циклом объекта. Так, когда я вызываю "ExecuteDataReader", он создает соединение, с переданным proc (есть перегрузка для params) выполняет его, выполняет делегат и затем убирает за собой.
public class User
{
public static List<User> GetAllUsers()
{
DataAccessWrapper daw = new DataAccessWrapper();
return (List<User>)(daw.ExecuteDataReader("MyProc", new ReaderDelegate(ReadList)));
}
protected static object ReadList(SQLDataReader dr)
{
List<User> retVal = new List<User>();
while(dr.Read())
{
User temp = new User();
temp.Prop1 = dr.GetString("Prop1");
temp.Prop2 = dr.GetInt("Prop2");
retVal.Add(temp);
}
return retVal;
}
}