Действительно интересный вопрос. Честно я не могу доказать, почему объекты хороши. Но я могу совместно использовать свое мнение, почему мне нравятся они. Код как
void exportOrder(Order order, String fileName){...};
не затронут, куда порядок прибыл из - от DB, из веб-запроса, от модульного теста, и т.д. Это заставляет этот метод более явно объявить то, чего точно это требует, вместо того, чтобы брать DataRow и документировать, какие столбцы это ожидает иметь и который вводит, они должны быть. То же применяется при реализации его так или иначе как хранимой процедуры - все еще необходимо продвинуть рекордный идентификатор к нему, в то время как это не необходимый должно присутствовать в DB.
Реализация этого метода была бы сделана на основе абстракции Порядка, не на основе того, как точно это представлено в DB. Большинство таких операций, которые я реализовал действительно, не зависит от того, как эти данные хранятся. Я действительно понимаю, что некоторые операции требуют связи со структурой DB для производительности и целей масштабируемости, просто по моему опыту, нет слишком большого количества из них. По моему опыту, очень часто достаточно знать, что у Человека есть .getFirstName () возвращающий Строку и .getAddress () возвращающий Адрес, и адрес имеет .getZipCode (), и т.д. - и не заботьтесь, какие таблицы являются involed, чтобы хранить те данные.
, Если необходимо иметь дело с такими проблемами как Вы описанный, как то, когда дополнительные разрывы столбца сообщают о производительности, затем для Ваших задач, DB является критической частью, и действительно необходимо быть максимально близки к нему. В то время как объекты могут обеспечить некоторые удобные абстракции, они могут скрыть некоторые важные детали также.
Масштабируемость является интересным моментом здесь - большинство веб-сайтов, которые требуют, чтобы огромная масштабируемость (как Facebook, Живой Журнал, flickr) имела тенденцию использовать аскетический DB подход, когда DB используется максимально редкий, и проблемы масштабируемости решены путем кэширования, особенно Использованием оперативной памяти. http://highscalability.com/ имеет некоторые интересные статьи о нем.
Обновление: чтобы увидеть, что на самом деле происходит, не прибегая к IL: Использование отражателя для понимания анонимных методов и захваченных переменных
Когда вы используете:
public Bar CreateBar()
{
return new Bar(x, () => y);
}
Вы неявно значение this.y
; поэтому с точки зрения делегата включена ссылка на Foo
. Таким образом, экземпляр Bar
(через делегата) сохраняет весь Foo
живым (не собираемым мусором) до тех пор, пока Bar
не станет доступным для сбора. 12143] В частности, компилятору нет необходимости (в этом случае) создавать дополнительный класс для обработки захваченных переменных; единственное, что требуется, это экземпляр Foo
, поэтому метод может быть сгенерирован на Foo
. Это было бы сложнее, если бы делегат включал локальные переменные (кроме this
).
Что касается сериализации ... ну, первое, что я бы сказал, это то, что сериализация делегатов - это очень очень плохая идея. Однако BinaryFormatter
будет обходить делегаты, и вы можете (теоретически) получить сериализованный Bar
, сериализованный Foo
и сериализованный делегат чтобы связать их - но только , если вы отметите Foo
как [Serializable]
.
Но я подчеркиваю - это плохая идея . Я редко использую BinaryFormatter
(по разным причинам), но люди, использующие его, часто спрашивают: «Почему он пытается сериализовать (какой-то случайный тип)». Обычно ответ такой: «вы публикуете мероприятие, другой способ исследовать это - использовать отражатель в режиме .NET 1.0 (то есть без его замены анонимными методами); тогда вы можете увидеть:
public Bar CreateBar()
{
return new Bar(this.x, new Func<int>(this.<CreateBar>b__0));
}
[CompilerGenerated]
private int <CreateBar>b__0()
{
return this.y;
}
Как видите; вещь, переданная в Bar
, является делегатом скрытого метода (называемого
) в текущем экземпляре ( this
). Таким образом, - это экземпляр текущего Foo
, который передается в Bar
.
public Bar CreateBar()
{
return new Bar(this.x, new Func<int>(this.<CreateBar>b__0));
}
[CompilerGenerated]
private int <CreateBar>b__0()
{
return this.y;
}
Как видите; вещь, переданная в Bar
, является делегатом скрытого метода (называемого
) в текущем экземпляре ( this
). Таким образом, - это экземпляр текущего Foo
, который передается в Bar
.
Создайте проект быстрой проверки для вывода значений, а затем просмотрите их. Он должен ответить на вопросы и, вероятно, побудить вас узнать что-то дополнительное в процессе. (Это то, что сделали большинство людей, которые ответят на ваш вопрос.)
У меня возникла ошибка при попытке сериализации, когда она отражала объект для сериализации.
мой пример:
[Serializable]
public class SerializeTest
{
//public SerializeTest(int a, Func<int> b)
//{
// this.a = a;
// this.b = b;
//}
public SerializeTest()
{
}
public int A
{
get
{
return a;
}
set
{
a = value;
}
}
public Func<int> B
{
get
{
return b;
}
set
{
b = value;
}
}
#region properties
private int a;
private Func<int> b;
#endregion
//serialize itself
public string Serialize()
{
MemoryStream memoryStream = new MemoryStream();
XmlSerializer xs = new XmlSerializer(typeof(SerializeTest));
using (StreamWriter xmlTextWriter = new StreamWriter(memoryStream))
{
xs.Serialize(xmlTextWriter, this);
xmlTextWriter.Flush();
//xmlTextWriter.Close();
memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
memoryStream.Seek(0, SeekOrigin.Begin);
StreamReader reader = new StreamReader(memoryStream);
return reader.ReadToEnd();
}
}
//deserialize into itself
public void Deserialize(string xmlString)
{
String XmlizedString = null;
using (MemoryStream memoryStream = new MemoryStream())
{
using (StreamWriter w = new StreamWriter(memoryStream))
{
w.Write(xmlString);
w.Flush();
XmlSerializer xs = new XmlSerializer(typeof(SerializeTest));
memoryStream.Seek(0, SeekOrigin.Begin);
XmlReader reader = XmlReader.Create(memoryStream);
SerializeTest currentConfig = (SerializeTest)xs.Deserialize(reader);
this.a = currentConfig.a;
this.b = currentConfig.b;
w.Close();
}
}
}
}
class Program
{
static void Main(string[] args)
{
SerializeTest test = new SerializeTest() { A = 5, B = ()=>67};
string serializedString = test.Serialize();
}
}
Вот ссылка на это ... немного сложнее: Сериализация анонимных делегатов
Я думаю, что x и y в объекте Foo будут захвачены как типы значений. Таким образом, закрытие, созданное для этого лямбда-выражения, не должно содержать ссылку на объект Foo. Таким образом, компилятор может создать класс для этого закрытия, например:
internal class CompilerGeneratedClassName
{
private int x;
private int y;
public CompilerGeneratedClassName(int x, int y)
{
this.x = x;
this.y = y;
}
public int CompilerGeneratedMethodName()
{
return this.y;
}
}
и
return new Bar(x, () => y);
могут быть заменены на
return new Bar(x,new CompilerGeneratedClassName(x,y).CompilerGeneratedMethodName);
Так что я не думаю, что в результате этого закрытия будет ссылка на объект Foo. Итак, объект Foo может быть собран. Я могу ошибаться. Единственное, что вы можете сделать, - это написать небольшую программу, скомпилировать ее и проверить сгенерированный IL с помощью инструмента ILDASM.