Ninject Factory Extension Memory Leak? - c#

I am using the following interface as a ToFactory() binding:
public interface ISamplerFactory
{
ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter);
}
When I bind ToFactory() I can successfully create the class but I then get a memory leak whereby the register, unregister and valueGetter parameters are held by a ConstructorArgument inside Ninject, which reference a target/parameter object inside the delegates. This keeps that target object from getting GC'd. I am using ContextPreservation extension too if that makes a difference. (See complete sample code below)
When I remove the "ToFactory()" bind and create a standard factory class, it works.
public class SamplerFactory : ISamplerFactory
{
private readonly IDistributionResolver _resolverFactory;
public SamplerFactory(IDistributionResolverFactory resolverFactory)
{
_resolverFactory = resolverFactory;
}
ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter)
{
return new SpecificSampler(_resolverFactory, register, unregister, valueGetter);
}
}
And my target objects inside the delegates are GC'd successfully.
Is there something I am doing wrong or isn't the Factory extension meant to handle these more complex arguments? I assume if I used the .WithConstructorArgument I would get the same outcome.
EDIT: Added all necessary bindings and rewrote my sample code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication
{
using System;
using Ninject;
using Ninject.Extensions.ContextPreservation;
using Ninject.Extensions.Factory;
public class Program
{
static void Main(string[] args)
{
new Program().Run();
}
public void Run()
{
var kernel = new StandardKernel(new NinjectSettings() { LoadExtensions = false });
kernel.Load(new FuncModule());
kernel.Load(new ContextPreservationModule());
kernel.Bind<IDistributionResolver>().To<DistributionResolver>(); // This is a constructor-less object.
kernel.Bind<ISampler>().To<SpecificSampler>();
kernel.Bind<ISamplerFactory>().ToFactory();
kernel.Bind<IInjected>().To<Injected>();
kernel.Bind<IDistributionResolver>().To<DistributionResolver>();
kernel.Bind<IDistributionResolverFactory>().ToFactory();
var s = new SomeObject();
var weakS = new WeakReference(s);
var factory = kernel.Get<ISamplerFactory>();
var sampler = CreateInstance(factory, s);
s = null;
factory = null;
sampler = null;
GC.Collect();
if (weakS.IsAlive)
throw new Exception();
}
private ISampler CreateInstance(ISamplerFactory factory, SomeObject someObject)
{
var x = factory.Create(y => someObject.Do += y, z => someObject.Do -= z, () => someObject.Query());
if (x == null)
throw new Exception();
return x;
}
public class SomeObject
{
public event EventHandler<ValueChangedEventArgs> Do;
public decimal? Query()
{
return 0;
}
}
public class SpecificSampler : ISampler
{
private readonly IDistributionResolverFactory resolver;
private readonly Action<EventHandler<ValueChangedEventArgs>> register;
private readonly Action<EventHandler<ValueChangedEventArgs>> unregister;
private Func<decimal?> _valueGetter;
public SpecificSampler(
IDistributionResolverFactory resolver, // This is injected
Action<EventHandler<ValueChangedEventArgs>> register, // The rest come from the factory inputs
Action<EventHandler<ValueChangedEventArgs>> unregister,
Func<decimal?> valueGetter)
{
this.resolver = resolver;
this.register = register;
this.unregister = unregister;
_valueGetter = valueGetter;
// Do Stuff;
}
}
public class ValueChangedEventArgs : EventArgs
{
}
public interface ISamplerFactory
{
ISampler Create(Action<EventHandler<ValueChangedEventArgs>> register, Action<EventHandler<ValueChangedEventArgs>> unregister, Func<decimal?> valueGetter);
}
public interface IDistributionResolverFactory
{
IDistributionResolver Create(IDictionary<string, string> picked);
}
public interface IDistributionResolver
{
}
private class DistributionResolver : IDistributionResolver
{
readonly IInjected _i;
readonly IDictionary<string, string> _picked;
public DistributionResolver(IInjected i, IDictionary<string, string> picked)
{
_i = i;
_picked = picked;
}
}
public interface ISampler
{
}
}
public interface IInjected
{
}
class Injected : IInjected
{
}
}

I tracked this down to a memory leak in Ninject Core:
https://github.com/ninject/ninject/issues/74

Related

Is it possible to create a Singleton factory class maintaining a dictionary for instances?

I have multiple classes that inherit from IPrint. I want to instantiate these classes using a factory but I want to maintain a single instance of each type.
Is this possible?
Please find my sample code below.
public interface IPrint
{
void DoPrint();
}
public class DigitalPrint : IPrint
{
public void DoPrint()
{
// logic
}
}
public class InkPrint : IPrint
{
public void DoPrint()
{
// logic
}
}
public class PrintFactory
{
private static IDictionary<IPrint, object> prints = new
Dictionary<IPrint, object>();
private PrintFactory()
{
}
public static IPrint GetPrint(PrintType type)
{
// return instance depending on type. Instantiate only once
//like singleton
// How to write so that it returns a single instance depending
//on type
return null;
}
}
public enum PrintType
{
DigitalPrint,
InkPrint
}
Can someone give me some idea if this is possible?
Thanks.
You can create IPrint instances when initializing Dictionary<PrintType, IPrint>:
private static IDictionary<PrintType, IPrint> prints =
new Dictionary<PrintType, IPrint> {
{ PrintType.DigitalPrint, new DigitalPrint() },
{ PrintType.InkPrint, new InkPrint() }
};
Getting print (thus print is a class, the same instance will be returned for each request):
public static IPrint GetPrint(PrintType type)
{
IPrint print;
if (!prints.TryGetValue(type, out print))
return null;
return print;
}
If you don't want to create IPrint instances until the client asks for them, you can use Dictionary<PrintType, Lazy<IPrint>>:
private static IDictionary<string, Lazy<IPrint>> prints =
new Dictionary<string, Lazy<IPrint>> {
{ PrintType.DigitalPrint, new Lazy<IPrint>(() => new DigitalPrint()) },
{ PrintType.InkPrint, new Lazy<IPrint>(() => new InkPrint()) }
};
Getting print (in this case only one instance of each IPrint type will be created, but not before someone tries to get the instance of that type):
public static IPrint GetPrint(PrintType type)
{
Lazy<IPrint> factory;
if (!prints.TryGetValue(type, out factory))
return null;
return factory.Value;
}
Though I would consider using dependency injection framework instead of implementing such functionality manually.
Further reading: Ninject or Autofac
Yes, it's possible.
This creates the IPrint's before they're needed. You could make them lazily created, instead.
public class Program
{
public static void Main(string[] args)
{
var factory = new PrintFactory();
Console.WriteLine(PrintFactory.GetPrint(PrintType.DigitalPrint));
Console.WriteLine(PrintFactory.GetPrint(PrintType.InkPrint));
}
}
public interface IPrint
{
void DoPrint();
}
public class DigitalPrint : IPrint
{
public void DoPrint()
{
// logic
}
}
public class InkPrint : IPrint
{
public void DoPrint()
{
// logic
}
}
public class PrintFactory
{
// Make the dictionary from PrintType to IPrint instead of IPrint to object
private static IDictionary<PrintType, IPrint> prints = new Dictionary<PrintType, IPrint>();
// Initialize prints in a static constructor.
static PrintFactory()
{
prints.Add(PrintType.DigitalPrint, new DigitalPrint());
prints.Add(PrintType.InkPrint, new InkPrint());
}
public static IPrint GetPrint(PrintType type)
{
if (!prints.ContainsKey(type))
{
// TODO: Maybe throw an exception or log?
}
return prints[type];
}
}
public enum PrintType
{
DigitalPrint,
InkPrint
}
I would get rid of the enum and make a generic method:
public static IPrint GetPrint<T>() where T : IPrint, new ()
{
foreach (var key in prints.Keys) {
if (key is T)
return null;
}
return new T();
}

Initializing ExportFactory using MEF

Scenario
Application has multiple parts.
Each part is in separate dll and implements interface IFoo
All such dlls are present in same directory (plugins)
The application can instantiate multiple instances of each part
Below is the code snippet for the interfaces, part(export) and the import. The problem I am running into is, the "factories" object is initialized with empty list.
However, if I try container.Resolve(typeof(IEnumerable< IFoo >)) I do get object with the part. But that doesn't serve my purpose (point 4). Can anyone point what I am doing wrong here?
public interface IFoo
{
string Name { get; }
}
public interface IFooMeta
{
string CompType { get; }
}
Implementation of IFoo in separate Dll
[ExportMetadata("CompType", "Foo1")]
[Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo1 : IFoo
{
public string Name
{
get { return this.GetType().ToString(); }
}
}
Main application that loads all the parts and instantiate them as needed
class PartsManager
{
[ImportMany]
private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;
public PartsManager()
{
IContainer container = ConstructContainer();
factories = (IEnumerable<ExportFactory<IFoo, IFooMeta>>)
container.Resolve(typeof(IEnumerable<ExportFactory<IFoo, IFooMeta>>));
}
private static IContainer ConstructContainer()
{
var catalog = new DirectoryCatalog(#"C:\plugins\");
var builder = new ContainerBuilder();
builder.RegisterComposablePartCatalog(catalog);
return builder.Build();
}
public IFoo GetPart(string compType)
{
var matchingFactory = factories.FirstOrDefault(
x => x.Metadata.CompType == compType);
if (factories == null)
{
return null;
}
else
{
IFoo foo = matchingFactory.CreateExport().Value;
return foo;
}
}
}
It seems to be an issue with ContainerBuilder. I tried alternate approach with CompositionContainer and it worked without hurdles. Pasting the code snippet for modified methods.
public PartsManager()
{
ConstructContainer();
}
private void ConstructContainer()
{
var catalog = new DirectoryCatalog(#"C:\plugins\");
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
container.SatisfyImportsOnce(this);
}
It appears that it's a known issue in Autofac, that is currently closed with "won't fix" resolution.
If you remove dependency from Autofac like below it will work:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.Linq;
using System.ComponentModel.Composition;
using System.Reflection;
namespace SO24132313
{
public interface IFoo
{
string Name { get; }
}
public interface IFooMeta
{
string CompType { get; }
}
[ExportMetadata("CompType", "Foo1")]
[Export(typeof(IFoo)), PartCreationPolicy(CreationPolicy.NonShared)]
public class Foo1 : IFoo
{
public string Name
{
get { return GetType().ToString(); }
}
}
class PartsManager
{
[ImportMany]
private IEnumerable<ExportFactory<IFoo, IFooMeta>> factories;
public PartsManager()
{
ConstructContainer(this);
}
private static void ConstructContainer(PartsManager p)
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var c = new CompositionContainer(catalog);
c.ComposeParts(p);
}
public IFoo GetPart(string compType)
{
var matchingFactory = factories.FirstOrDefault(
x => x.Metadata.CompType == compType);
if (factories == null)
{
return null;
}
else
{
IFoo foo = matchingFactory.CreateExport().Value;
return foo;
}
}
}
class Program
{
static void Main(string[] args)
{
PartsManager a = new PartsManager();
IFoo bla = a.GetPart("Foo1");
Console.WriteLine(bla);
}
}
}

How to export parts from an object not instantiated by the MEF container

Introduction
Class SessionModel is a service locator providing several services (I am going to elaborate my system architecture in the future, but for now I need to do it that way).
Code
I edited the following code part to be a Short, Self Contained, Correct (Compilable), Example (SSCCE):
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var sessionModel = new SessionModel(3);
// first case (see text down below):
var compositionContainer = new CompositionContainer();
// second case (see text down below):
//var typeCatalog = new TypeCatalog(typeof (SessionModel));
//var compositionContainer = new CompositionContainer(typeCatalog);
compositionContainer.ComposeExportedValue(sessionModel);
var someService = compositionContainer.GetExportedValue<ISomeService>();
someService.DoSomething();
}
}
public class SessionModel
{
private int AValue { get; set; }
[Export]
public ISomeService SomeService { get; private set; }
public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
SomeService = new SomeService();
}
}
public interface ISomeService
{
void DoSomething();
}
public class SomeService : ISomeService
{
public void DoSomething()
{
Console.WriteLine("DoSomething called");
}
}
}
Problem
I would like MEF to consider the parts (i.e. SomeService) exported by the service locator when composing other parts, but unfortunately this does not work.
First Case
When I try to get the exported value for ISomeService there is a System.ComponentModel.Composition.ImportCardinalityMismatchException telling me there are no exports with this contract name and required type identity (ConsoleApplication1.ISomeService).
Second Case
If I create the CompositionContainer using the TypeCatalog the exception is slightly different. It is a System.ComponentModel.Composition.CompositionException telling me MEF doesn't find a way to create a ConsoleApplication1.SessionModel (which is right and the reason why I am doing it myself).
Additional Information
mefx says for both cases:
[Part] ConsoleApplication1.SessionModel from: DirectoryCatalog (Path=".")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
[Part] ConsoleApplication1.SessionModel from: AssemblyCatalog (Assembly="ConsoleApplication1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
[Export] ConsoleApplication1.SessionModel.SomeService (ContractName="ConsoleApplication1.ISomeService")
What do I have to do? Is this possible with MEF or do I have to use Unity or StructureMap, or something else? Can this be done implementing an ExportProvider?
OK, that's how I did it:
I implemented my own SessionModelExportProvider finding exports in my SessionModel (see code below). Class SessionModelExport is just for holding the export data and – instead of creating an instance of a service – returning the value of the property of the SessionModel.
public class SessionModelExportProvider : ExportProvider
{
private List<Export> Exports { get; set; }
public SessionModelExportProvider(SessionModel sessionModel)
{
// get all the properties of the session model having an Export attribute
var typeOfSessionModel = typeof (SessionModel);
PropertyInfo[] properties = typeOfSessionModel.GetProperties();
var propertiesHavingAnExportAttribute =
from p in properties
let exportAttributes = p.GetCustomAttributes(typeof (ExportAttribute), false)
where exportAttributes.Length > 0
select new
{
PropertyInfo = p,
ExportAttributes = exportAttributes
};
// creating Export objects for each export
var exports = new List<Export>();
foreach (var propertyHavingAnExportAttribute in propertiesHavingAnExportAttribute)
{
var propertyInfo = propertyHavingAnExportAttribute.PropertyInfo;
foreach (ExportAttribute exportAttribute in propertyHavingAnExportAttribute.ExportAttributes)
{
string contractName = exportAttribute.ContractName;
if (string.IsNullOrEmpty(contractName))
{
Type contractType = exportAttribute.ContractType ?? propertyInfo.PropertyType;
contractName = contractType.FullName;
}
var metadata = new Dictionary<string, object>
{
{CompositionConstants.ExportTypeIdentityMetadataName, contractName},
{CompositionConstants.PartCreationPolicyMetadataName, CreationPolicy.Shared}
};
var exportDefinition = new ExportDefinition(contractName, metadata);
var export = new SessionModelExport(sessionModel, propertyInfo, exportDefinition);
exports.Add(export);
}
}
Exports = exports;
}
protected override IEnumerable<Export> GetExportsCore(ImportDefinition definition,
AtomicComposition atomicComposition)
{
return Exports.Where(e => definition.IsConstraintSatisfiedBy(e.Definition));
}
}
public class SessionModelExport : Export
{
private readonly SessionModel sessionModel;
private readonly PropertyInfo propertyInfo;
private readonly ExportDefinition definition;
public SessionModelExport(SessionModel sessionModel, PropertyInfo propertyInfo, ExportDefinition definition)
{
this.sessionModel = sessionModel;
this.propertyInfo = propertyInfo;
this.definition = definition;
}
public override ExportDefinition Definition
{
get { return definition; }
}
protected override object GetExportedValueCore()
{
var value = propertyInfo.GetValue(sessionModel, null);
return value;
}
}
The problem is that the SomeService is an instance property. You could have several SessionModel objects in your system, and MEF would have no way of knowing which SessionModel is returning the ISomeService instance that is supposed to be matched to an import.
Instead, just make SessionModel a static class and SomeService a static property. Alternatively, make SessionModel a singleton. The SomeService property would still be static, but would export the service from the one-and-only instance of SessionModel.
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.ReflectionModel;
using System.Reflection;
using System.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var catalogs = new AggregateCatalog();
var catalog = new System.ComponentModel.Composition.Hosting.AssemblyCatalog(Assembly.GetExecutingAssembly());
catalogs.Catalogs.Add(catalog);
var sessionModel = new SessionModel(3);
var container = new CompositionContainer(catalog);
ISomeService someService = container.GetExportedValueOrDefault<ISomeService>(sessionModel.cname);
if (someService != null)
{
someService.DoSomething();
}
}
}
public class SessionModel
{
private int AValue { get; set; }
//[Import("One",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel(int aValue)
{
AValue = aValue;
// of course, there is much more to do here in reality:
}
public string cname { get { return "One"; } }
}
public class SessionModel1
{
private int AValue { get; set; }
//[Import("Two",typeof(ISomeService))]
//public ISomeService SomeService { get; private set; }
public SessionModel1(int aValue)
{
AValue = aValue;
}
public string cname { get { return "Two"; } }
}
public interface ISomeService
{
void DoSomething();
}
[Export("One",typeof(ISomeService))]
public class SomeService : ISomeService
{
public SomeService()
{
Console.WriteLine("Some Service Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called");
Console.ReadKey();
}
}
[Export("Two",typeof(ISomeService))]
public class SomeService1 : ISomeService
{
public SomeService1()
{
Console.WriteLine("Some Service1 Called");
}
public void DoSomething()
{
Console.WriteLine("DoSomething called 1");
Console.ReadKey();
}
}
}
First case: By passing sessionModel to ComposeExportedValue you add a part of type SessionModel and not of ISomeService. To make this case work you nee to pass the service to ComposeExportedValue.
compositionContainer.ComposeExportedValue(sessionModel.SomeService);
Second case: In this case you leave the creation of parts to the container. The container can create new parts if there is either a parameter-less constructor or a constructor with parameters decorated with the ImportingConstructorAttribute. This most probably means that you will need to change your design a bit.
Personally I would go with the first case, but try to keep this to a minimum. After all the normal (and suggested) usage of MEF is letting the container create and handle parts.

How to pass a parameter indirectly in Autofac

I have a dependency being injected via Func<Owned<OwnedDependency>>. One of its dependencies requires a parameter that I will only have at the point of constructing OwnedDependency.
public class OwnedDependency
{
public OwnedDependency(IDependency1 dependency)
{
}
}
public interface IDependency1
{
}
public class Dependency1 : IDependency1
{
public Dependency1(MyParameter parameter)
{
}
}
public class MyClass
{
private readonly Func<Owned<OwnedDependency>> m_ownedDependencyFactory;
public MyClass(Func<Owned<OwnedDependency>> ownedDependencyFactory)
{
m_ownedDependencyFactory = ownedDependencyFactory;
}
public void CreateOwnedDependency()
{
var parameter = new MyParameter(...);
// ** how to setup parameter with the container? **
using (var ownedDependency = m_ownedDependencyFactory())
{
}
}
}
I can't work out a clean way of setting up the instance of MyParameter.
One approach I have explored is to inject ILifetimeScope into MyClass and then do something like:
var parameter = new MyParameter(...);
using (var newScope = m_lifetimeScope.BeginLifetimeScope())
{
newScope.Resolve<IDependency1>(new TypedParameter(typeof(MyParameter), parameter));
var ownedDependency = newScope.Resolve<OwnedDependency>();
// ...
}
but the container is becoming unnecessarily intrusive. Ideally what I would like to do is inject Func<IDependency1, Owned<OwnedDependency>> and the container be willing to use parameters passed in to satisfy any necessary dependency, not just the ones on OwnedDependency.
What about doing the resolution in two steps with using another factory for IDependency1:
public class MyClass
{
private Func<MyParameter, IDependency1> dependency1Factory;
private Func<IDependency1, Owned<OwnedDependency>> ownedDependencyFactory;
public MyClass(
Func<MyParameter, IDependency1> dependency1Factory,
Func<IDependency1, Owned<OwnedDependency>> ownedDependencyFactory)
{
this.dependency1Factory = dependency1Factory;
this.ownedDependencyFactory = ownedDependencyFactory;
}
public void CreateOwnedDependency()
{
var parameter = new MyParameter();
using (var owned = ownedDependencyFactory(dependency1Factory(parameter)))
{
}
}
}

Create an alternative to serializable anonymous delegates

there have been quite some posts about this, all trying to serialize a Func delegate.
But could someone think of an alternative, when the use of the delegate is always clear?
We have a generic create command, which takes a delegate as paramater in the constructor. This delegate will create the Item for the create command:
public class CreateCommand<T> : Command
{
public T Item;
protected Func<T> Constructor;
public ClientCreateCommand(Func<T> constructor)
{
Constructor = constructor;
}
public override void Execute()
{
Item = Constructor();
}
}
The command is used like this:
var c = new CreateCommand<MyType>( () => Factory.CreateMyType(param1, param2, ...) );
History.Insert(c);
Then the History serializes the command and sends it to the server. ofc the delegate can't be serialized as is and we get an exception.
Now could someone think of a very simple Constructor class that can be serialized and does the same job than the lambda expresseion? Means it takes a list of paramters and returns an instance of type T, that we then can write somethink like this:
var constructor = new Constructor<MyType>(param1, param2, ...);
var c = new CreateCommand<MyType>(constructor);
History.Insert(c);
How would the Constructor class look like? Thanks for any ideas!
EDIT(2): I've provided a couple of complete example implementations. They are categorized below as "Implementation 1" and "Implementation 2".
Your delegate is essentially a factory. You could define a factory interface and create a class that implements that interface for your Item class. Below is an example:
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class ExampleItemFactory : IFactory<T>
{
public int Param1 { get; set; }
public string Param2 { get; set; }
#region IFactory<T> Members
public Item Create()
{
return new Item(this.Param1, this.Param2);
}
#endregion
}
public class CreateCommand<T> : Command
{
public T Item;
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> factory)
{
_ItemFactory = factory;
}
public override void Execute()
{
Item = _ItemFactory.Create();
}
}
You would utilize this code in the following manner:
IFactory<Item> itemFactory = new ExampleItemFactory { Param1 = 5, Param2 = "Example!" };
CreateCommand<Item> command = new CreateCommand<Item>(itemFactory);
command.Execute();
EDIT(1): The specific implementations of IFactory<T> that your application needs will be up to you. You could create specific factory classes for each class that you need, or you could create some kind of factory that dynamically creates an instance using, for example, the Activator.CreateInstance function or perhaps using some kind of Inversion of Control framework such as Spring or StructureMap.
Below is a complete example implementation that uses two factory implementations. One implementation can create any type given an array of arguments using that type's constructor with matching parameters. Another implementation creates any type that has been registered with my "Factory" class.
The Debug.Assert statements ensure that everything is behaving as intended. I ran this application without error.
Implementation 1
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
public class Factory
{
static Dictionary<Type, Func<object[], object>> _DelegateCache = new Dictionary<Type, Func<object[], object>>();
public static void Register<T>(Func<object[], object> #delegate)
{
_DelegateCache[typeof(T)] = #delegate;
}
public static T CreateMyType<T>(params object[] args)
{
return (T)_DelegateCache[typeof(T)](args);
}
}
public interface IFactory<T>
{
T Create();
}
[Serializable]
public class CreateCommand<T> : Command
{
public T Item { get; protected set; }
protected IFactory<T> _ItemFactory;
public CreateCommand(IFactory<T> itemFactory)
{
this._ItemFactory = itemFactory;
}
public override void Execute()
{
this.Item = this._ItemFactory.Create();
}
}
// This class is a base class that represents a factory capable of creating an instance using a dynamic set of arguments.
[Serializable]
public abstract class DynamicFactory<T> : IFactory<T>
{
public object[] Args { get; protected set; }
public DynamicFactory(params object[] args)
{
this.Args = args;
}
public DynamicFactory(int numberOfArgs)
{
if (numberOfArgs < 0)
throw new ArgumentOutOfRangeException("numberOfArgs", "The numberOfArgs parameter must be greater than or equal to zero.");
this.Args = new object[numberOfArgs];
}
#region IFactory<T> Members
public abstract T Create();
#endregion
}
// This implementation uses the Activator.CreateInstance function to create an instance
[Serializable]
public class DynamicConstructorFactory<T> : DynamicFactory<T>
{
public DynamicConstructorFactory(params object[] args) : base(args) { }
public DynamicConstructorFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return (T)Activator.CreateInstance(typeof(T), this.Args);
}
}
// This implementation uses the Factory.CreateMyType function to create an instance
[Serializable]
public class MyTypeFactory<T> : DynamicFactory<T>
{
public MyTypeFactory(params object[] args) : base(args) { }
public MyTypeFactory(int numberOfArgs) : base(numberOfArgs) { }
public override T Create()
{
return Factory.CreateMyType<T>(this.Args);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PrivateConstructorExample
{
private int _A;
private string _B;
private float _C;
private PrivateConstructorExample()
{
}
public static void Register()
{
// register a delegate with the Factory class that will construct an instance of this class using an array of arguments
Factory.Register<PrivateConstructorExample>((args) =>
{
if (args == null || args.Length != 3)
throw new ArgumentException("Expected 3 arguments.", "args");
if (!(args[0] is int))
throw new ArgumentException("First argument must be of type System.Int32.", "args[0]");
if (!(args[1] is string))
throw new ArgumentException("Second argument must be of type System.String.", "args[1]");
if (!(args[2] is float))
throw new ArgumentException("Third argument must be of type System.Single.", "args[2]");
var instance = new PrivateConstructorExample();
instance._A = (int)args[0];
instance._B = (string)args[1];
instance._C = (float)args[2];
return instance;
});
}
}
class Program
{
static void Main(string[] args)
{
var factory1 = new DynamicConstructorFactory<DefaultConstructorExample>(null);
var command1 = new CreateCommand<DefaultConstructorExample>(factory1);
var factory2 = new DynamicConstructorFactory<NoDefaultConstructorExample>(3);
factory2.Args[0] = 5;
factory2.Args[1] = "ABC";
factory2.Args[2] = 7.1f;
var command2 = new CreateCommand<NoDefaultConstructorExample>(factory2);
PrivateConstructorExample.Register(); // register this class so that it can be created by the Factory.CreateMyType function
var factory3 = new MyTypeFactory<PrivateConstructorExample>(3);
factory3.Args[0] = 5;
factory3.Args[1] = "ABC";
factory3.Args[2] = 7.1f;
var command3 = new CreateCommand<PrivateConstructorExample>(factory3);
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<NoDefaultConstructorExample>(command2);
VerifySerializability<PrivateConstructorExample>(command3);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}
EDIT(2): After re-reading the question, I think I got a better idea of what the asker was really trying to get at. Essentially, we still want to take advantage of the flexibility offered by lambda expressions / anonymous delegates, but avoid the serialization issues.
Below is another example implementation that utilizes a Factory<T> class to store delegates used to return instances of type T.
Implementation 2
[Serializable]
public abstract class Command
{
public abstract void Execute();
}
[Serializable]
public abstract class CreateCommand<T> : Command
{
public T Item { get; protected set; }
}
public class Factory<T>
{
private static readonly object _SyncLock = new object();
private static Func<T> _CreateFunc;
private static Dictionary<string, Func<T>> _CreateFuncDictionary;
/// <summary>
/// Registers a default Create Func delegate for type <typeparamref name="T"/>.
/// </summary>
public static void Register(Func<T> createFunc)
{
lock (_SyncLock)
{
_CreateFunc = createFunc;
}
}
public static T Create()
{
lock (_SyncLock)
{
if(_CreateFunc == null)
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered as the default delegate for type [{1}]..", typeof(Func<T>).FullName, typeof(T).FullName));
return _CreateFunc();
}
}
/// <summary>
/// Registers a Create Func delegate for type <typeparamref name="T"/> using the given key.
/// </summary>
/// <param name="key"></param>
/// <param name="createFunc"></param>
public static void Register(string key, Func<T> createFunc)
{
lock (_SyncLock)
{
if (_CreateFuncDictionary == null)
_CreateFuncDictionary = new Dictionary<string, Func<T>>();
_CreateFuncDictionary[key] = createFunc;
}
}
public static T Create(string key)
{
lock (_SyncLock)
{
Func<T> createFunc;
if (_CreateFuncDictionary != null && _CreateFuncDictionary.TryGetValue(key, out createFunc))
return createFunc();
else
throw new InvalidOperationException(string.Format("A [{0}] delegate must be registered with the given key \"{1}\".", typeof(Func<T>).FullName, key));
}
}
}
[Serializable]
public class CreateCommandWithDefaultDelegate<T> : CreateCommand<T>
{
public override void Execute()
{
this.Item = Factory<T>.Create();
}
}
[Serializable]
public class CreateCommandWithKeyedDelegate<T> : CreateCommand<T>
{
public string CreateKey { get; set; }
public CreateCommandWithKeyedDelegate(string createKey)
{
this.CreateKey = createKey;
}
public override void Execute()
{
this.Item = Factory<T>.Create(this.CreateKey);
}
}
[Serializable]
class DefaultConstructorExample
{
public DefaultConstructorExample()
{
}
}
[Serializable]
class NoDefaultConstructorExample
{
public NoDefaultConstructorExample(int a, string b, float c)
{
}
}
[Serializable]
class PublicPropertiesExample
{
public int A { get; set; }
public string B { get; set; }
public float C { get; set; }
}
class Program
{
static void Main(string[] args)
{
// register delegates for each type
Factory<DefaultConstructorExample>.Register(() => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register(() => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register(() => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands
var command1 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command2 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
var command3 = new CreateCommandWithDefaultDelegate<DefaultConstructorExample>();
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command1);
VerifySerializability<DefaultConstructorExample>(command2);
VerifySerializability<DefaultConstructorExample>(command3);
// register additional delegates for each type, distinguished by key
Factory<DefaultConstructorExample>.Register("CreateCommand", () => new DefaultConstructorExample());
Factory<NoDefaultConstructorExample>.Register("CreateCommand", () => new NoDefaultConstructorExample(5, "ABC", 7.1f));
Factory<PublicPropertiesExample>.Register("CreateCommand", () => new PublicPropertiesExample() { A = 5, B = "ABC", C = 7.1f });
// create commands, passing in the create key to the constructor
var command4 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command5 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
var command6 = new CreateCommandWithKeyedDelegate<DefaultConstructorExample>("CreateCommand");
// verify that each command can be serialized/deserialized and that the creation logic works
VerifySerializability<DefaultConstructorExample>(command4);
VerifySerializability<DefaultConstructorExample>(command5);
VerifySerializability<DefaultConstructorExample>(command6);
}
static void VerifySerializability<T>(CreateCommand<T> originalCommand)
{
var serializer = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
using (var stream = new System.IO.MemoryStream())
{
System.Diagnostics.Debug.Assert(originalCommand.Item == null); // assert that originalCommand does not yet have a value for Item
serializer.Serialize(stream, originalCommand); // serialize the originalCommand object
stream.Seek(0, System.IO.SeekOrigin.Begin); // reset the stream position to the beginning for deserialization
// deserialize
var deserializedCommand = serializer.Deserialize(stream) as CreateCommand<T>;
System.Diagnostics.Debug.Assert(deserializedCommand.Item == null); // assert that deserializedCommand still does not have a value for Item
deserializedCommand.Execute();
System.Diagnostics.Debug.Assert(deserializedCommand.Item != null); // assert that deserializedCommand now has a value for Item
}
}
}

Categories

Resources