Уже существует большое хорошее обсуждение здесь, и я немного опаздываю стороне, но я хотел добавить несколько точек сам.
class SomeObject : IDisposable {
IntPtr _SomeNativeHandle;
FileStream _SomeFileStream;
// Something useful here
~ SomeObject() {
Dispose(false);
}
public void Dispose() {
Dispose(true);
}
protected virtual void Dispose(bool disposing) {
if(disposing) {
GC.SuppressFinalize(this);
//Because the object was explicitly disposed, there will be no need to
//run the finalizer. Suppressing it reduces pressure on the GC
//The managed reference to an IDisposable is disposed only if the
_SomeFileStream.Dispose();
}
//Regardless, clean up the native handle ourselves. Because it is simple a member
// of the current instance, the GC can't have done anything to it,
// and this is the onlyplace to safely clean up
if(IntPtr.Zero != _SomeNativeHandle) {
NativeMethods.CloseHandle(_SomeNativeHandle);
_SomeNativeHandle = IntPtr.Zero;
}
}
}
Это - простая версия, но существует много нюансов, которые могут сбить Вас с толку на этом шаблоне.
, По-моему, намного лучше полностью постараться не иметь любые типы, которые непосредственно содержат и доступные ссылки и собственные ресурсы, которые могут потребовать завершения. SafeHandles обеспечивают очень очевидный способ выполнения этого путем инкапсуляции собственных ресурсов в доступные, которые внутренне обеспечивают их собственное завершение (наряду со многими другими преимуществами как удаление окна во время P/Invoke, где собственный дескриптор мог быть потерян из-за асинхронного исключения).
Просто определение SafeHandle делает это Тривиальным:
private class SomeSafeHandle
: SafeHandleZeroOrMinusOneIsInvalid {
public SomeSafeHandle()
: base(true)
{ }
protected override bool ReleaseHandle()
{ return NativeMethods.CloseHandle(handle); }
}
Позволяет Вам упрощать содержание типа до:
class SomeObject : IDisposable {
SomeSafeHandle _SomeSafeHandle;
FileStream _SomeFileStream;
// Something useful here
public virtual void Dispose() {
_SomeSafeHandle.Dispose();
_SomeFileStream.Dispose();
}
}
Если вы говорите о TCP, то нет - ни один API сокетов, который я видел, не позволяет вам это сделать.
Вам необходимо реализовать подтверждение в протоколе вашего приложения, если вам нужно убедитесь, что другой конец получил (и, возможно, обработал) ваши данные.
Подтверждение для пакета находится на транспортном уровне (значительно ниже уровня приложения). У вас даже нет гарантии, что весь ваш буфер принадлежит его собственному пакету в сети. Что вы пытаетесь сделать?
Если вы используете setsockopt ()
для понижения SO_SNDBUF
до значения, достаточного только для отправки одного пакета, то следующий отправит ( )
на этом сокете должна блокироваться до тех пор, пока не будет подтвержден предыдущий пакет. Однако, согласно tcp (7)
, размер буфера сокета должен быть установлен до listen ()
/ connect ()
.
Преимущества:
Недостатки:
Уже упоминалась кривая обучения. Вы можете начать использовать NHibernate очень быстро, но вам потребуются месяцы, чтобы освоить его. Я настоятельно рекомендую прочитать книгу Manning NHibernate.
Написание сопоставления XML может быть очень утомительным, особенно для больших баз данных с сотнями и тысячами таблиц, представлений и хранимых процедур. Да, есть инструменты, которые помогут вам сгенерировать эти сопоставления, но вам все равно придется проделать довольно много ручной работы. Fluent NHibernate , похоже, упрощает этот процесс, избавляясь от сопоставлений XML, как и Castle ActiveRecord (AR, хотя его невозможно использовать для анемичной области, поскольку вы определяете сопоставления в атрибутах в классах модели
В некоторых сценариях производительность может быть низкой. Например, крупные оптовые операции. Для тех, кому, возможно, придется использовать IStatelessSession, но это неудобно, по крайней мере, чтобы сказать ...
Весь смысл использования TCP состоит в том, чтобы скрыть этот индивидуальный ACK от приложений. Если вам нужно обнаруживать каждый ACK, реализуйте свой собственный протокол, используя UDP или IP. TCP наверное излишество. Или вы можете подняться по стеку и использовать протокол вроде HTTP в качестве транспорта.
TCP обычно требует, чтобы вы синхронизировали получателя и отправителя на уровне приложения. Комбинации настроек SO_SNDBUF
или TCP_NODELAY
сами по себе вряд ли решат проблему полностью. Это связано с тем, что объем данных, которые могут быть «в полете» до того, как send ()
заблокируется, более или менее равен сумме:
CWIN
) и размеры окна приема ( RWIN
). Отправитель TCP постоянно настраивает размер окна перегрузки в соответствии с условиями сети, поскольку TCP переходит между режимами медленного запуска, предотвращения перегрузки, быстрого восстановления и быстрой повторной передачи. И, ACK
, но приложение еще не увидело. Другими словами, после того, как получатель прекратит считывать данные из сокета, send ()
будет блокироваться только в следующих случаях:
ACK
, ACK
данные до предела перегрузки или окна приема, и Целью алгоритмов, используемых в TCP, является создание эффекта текущего потока байтов, а не последовательности пакетов. В общем, он пытается как можно больше скрыть тот факт, что передача вообще квантуется в пакеты, и большинство API сокетов это отражают. Одна из причин этого заключается в том, что сокеты могут вообще не быть реализованы поверх TCP (или даже IP): рассмотрите сокет домена Unix, который использует тот же API.
Попытка полагаться на базовые детали реализации TCP для поведения приложения является вообще не рекомендуется. Придерживайтесь синхронизации на уровне приложения.
Если задержка вызывает беспокойство в ситуации, когда вы выполняете синхронизацию, вы также можете прочитать о взаимодействиях между Nagle »