Что интересно в C #, относящемся к этой теме, так это то, что ограничение new () для универсальных типов, указанных в определении класса, вынуждает типы, которые обрабатываются универсальным типом контейнера, реализовывать конструктор без параметров. Ограничение new () необходимо только тогда, когда предполагается создать экземпляр типа T, как в GenericType<T>
, внутри класса. Мне кажется, что это явно в поддержку фабрик классов, особенно фабрик, которые производят универсальные типы.
Чтобы перевернуть это требование, в Windows Communication Foundation (WCF) есть класс ChannelFactory, который определяет следующий статический метод фабрики:
public static TChannel CreateChannel(Binding binding, EndpointAddress endpointAddress, Uri via)
{
ChannelFactory<TChannel> factory = new ChannelFactory<TChannel>(binding);
if (factory.HasDuplexOperations())
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxInvalidStaticOverloadCalledForDuplexChannelFactory1", new object[] { factory.channelType.Name })));
}
TChannel channel = factory.CreateChannel(endpointAddress, via);
ChannelFactory<TChannel>.SetFactoryToAutoClose(channel);
return channel;
}
Если вы посмотрите в Reflector на дизассемблирование класса (System.ServiceModel assembly & System.ServiceModel.Channels space), вы заметите, что «new ()» не используется в качестве ограничения.
Это потому, что метод CreateChannel использует typeof (TChannel), чтобы делегировать создание объекта дальше по цепочке ...
public virtual TChannel CreateChannel(EndpointAddress address, Uri via)
{
TChannel local;
bool traceOpenAndClose = base.TraceOpenAndClose;
try
{
using (ServiceModelActivity activity = (DiagnosticUtility.ShouldUseActivity && base.TraceOpenAndClose) ? ServiceModelActivity.CreateBoundedActivity() : null)
{
if (DiagnosticUtility.ShouldUseActivity)
{
ServiceModelActivity.Start(activity, this.OpenActivityName, this.OpenActivityType);
base.TraceOpenAndClose = false;
}
if (address == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("address");
}
if (base.HasDuplexOperations())
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString("SFxCreateNonDuplexChannel1", new object[] { base.Endpoint.Contract.Name })));
}
base.EnsureOpened();
local = (TChannel) this.ServiceChannelFactory.CreateChannel(typeof(TChannel), address, via);
}
}
finally
{
base.TraceOpenAndClose = traceOpenAndClose;
}
return local;
}
Вы можете проследить цепочку делегирования еще на несколько уровней по мере того, как класс Type передается до тех пор, пока, наконец, не будет вызван следующий метод:
RemotingServices.CreateTransparentProxy(this, classToProxy, stub, stubData);
Это чрезвычайно запутанно, но это самая сложная фабрика, которую я когда-либо видел. Интересно, что все махинации заканчиваются тем, что WCF создает класс RealProxy из пространства имен System.Runtime.Remoting.Proxies.
В заключение, фабрики предназначены для объектов, которые имеют большую сложность или нуждаются в извлечении выгоды из построения динамического типа.