Assume I have a plugin interface like this:
// PluginInterface.cs
interface Plugin
{
bool Check_When_Loaded(string q);
}
static class PluginList
{
public static List<Plugin> list = new List<Plugin>();
}
And I use it in MainWindow.cs:
// MainWindow.cs
private void Window_Loaded(object sender, RoutedEventArgs e)
{
foreach (var p in PluginList.list)
{
if (p.Check_When_Loaded(q.Text)) break;
}
}
Assume I write a plugin LovelyPlugin.cs:
// LovelyPlugin.cs
class LovelyPlugin : Plugin
{
public bool Check_When_Loaded(string q)
{
return true;
}
}
What I need is when I add LovelyPlugin.cs to C# project then complie, a 'LovelyPlugin' instance is added automaticly to PluginList.list, and if I remove this file then complie, there is no trace of LovelyPlugin in application at all.
I have a C# solution that have some simliar project (Light, Standard, Extra,...). All the difference between them is one have or doesn't have some plugin file. All .cs files is add as link to all these project and I want to build all these project concurently.
I can use #define and #if condition then build each project seperately. But I wonder if there is any way to fit my need just by add/remove plugin file without make any change in other source code file for each project. Any help would be appreciated!
You could use MEF...
Start by referencing System.ComponentModel.Composition
Read up on the MEF documentation regarding Imports and Exports. In your case, the Plugins are "Exports". We can use the [InheritedExport] attribute to allow every concrete object that implements IPlugin to be exportable.
// IPlugin.cs
using System.ComponentModel.Composition;
[InheritedExport]
public interface IPlugin
{
bool Check_When_Loaded(string q);
}
Your concrete implementation of IPlugin doesn't change.
// LovelyPlugin.cs
class LovelyPlugin : IPlugin
{
public bool Check_When_Loaded(string q)
{
return true;
}
}
I eliminated your static PluginList class to simplify the example. Below you can see how the Main Form is "Importing" any implmentations of IPlugin found in the Assembly. If you add (or remove) additional concrete implementations of IPlugin and recompile, the list will reflect accordingly.
// MainWindow.cs
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
public partial class Form1 : Form
{
[ImportMany]
public List<IPlugin> list = new List<IPlugin>();
public Form1()
{
InitializeComponent();
}
private void WindowLoaded(object sender, EventArgs e)
{
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
foreach (var p in list)
{
if (p.Check_When_Loaded(this.Name)) break;
}
}
}
Add this to your PluginList class:
// using System.Reflection;
static PluginList()
{
list.AddRange(
from t in Assembly.GetAssembly(typeof(PluginList)).GetTypes()
where t.IsClass && t.GetInterfaces().Contains(typeof(Plugin))
select new Func<Plugin>(() => {
try
{
return (Plugin)t.GetConstructor(new Type[] { }).Invoke(new object[] { });
}
catch
{
return null;
}
})());
}
Essentially at runtime this will:
Get all types in the current project (the from line).
Filter these types to only include classes that implement your Plugin interface (the where line).
It attempts to construct one of each of these plugin classes with a default constructor (zero-argument) in the select line. If you want exceptions for failed constructors, you can simply change the return null;.
Add all such constructed plugins to your list.
Related
C#. I have a base class called FileProcessor:
class FileProcessor {
public Path {get {return m_sPath;}}
public FileProcessor(string path)
{
m_sPath = path;
}
public virtual Process() {}
protected string m_sath;
}
Now I'd like to create to other classes ExcelProcessor & PDFProcessor:
class Excelprocessor: FileProcessor
{
public void ProcessFile()
{
//do different stuff from PDFProcessor
}
}
Same for PDFProcessor, a file is Excel if Path ends with ".xlsx" and pdf if it ends with ".pdf". I could have a ProcessingManager class:
class ProcessingManager
{
public void AddProcessJob(string path)
{
m_list.Add(Path;)
}
public ProcessingManager()
{
m_list = new BlockingQueue();
m_thread = new Thread(ThreadFunc);
m_thread.Start(this);
}
public static void ThreadFunc(var param) //this is a thread func
{
ProcessingManager _this = (ProcessingManager )var;
while(some_condition) {
string fPath= _this.m_list.Dequeue();
if(fPath.EndsWith(".pdf")) {
new PDFProcessor().Process();
}
if(fPath.EndsWith(".xlsx")) {
new ExcelProcessor().Process();
}
}
}
protected BlockingQueue m_list;
protected Thread m_thread;
}
I am trying to make this as modular as possible, let's suppose for example that I would like to add a ".doc" processing, I'd have to do a check inside the manager and implement another DOCProcessor.
How could I do this without the modification of ProcessingManager? and I really don't know if my manager is ok enough, please tell me all your suggestions on this.
I'm not really aware of your problem but I'll try to give it a shot.
You could be using the Factory pattern.
class FileProcessorFactory {
public FileProcessor getFileProcessor(string extension){
switch (extension){
case ".pdf":
return new PdfFileProcessor();
case ".xls":
return new ExcelFileProcessor();
}
}
}
class IFileProcessor{
public Object processFile(Stream inputFile);
}
class PdfFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
class ExcelFileProcessor : IFileProcessor {
public Object processFile(Stream inputFile){
// do things with your inputFile
}
}
This should make sure you are using the FileProcessorFactory to get the correct processor, and the IFileProcessor will make sure you're not implementing different things for each processor.
and implement another DOCProcessor
Just add a new case to the FileProcessorFactory, and a new class which implements the interface IFileProcessor called DocFileProcessor.
You could decorate your processors with custom attributes like this:
[FileProcessorExtension(".doc")]
public class DocProcessor()
{
}
Then your processing manager could find the processor whose FileProcessorExtension property matches your extension, and instantiate it reflexively.
I agree with Highmastdon, his factory is a good solution. The core idea is not to have any FileProcessor implementation reference in your ProcessingManager anymore, only a reference to IFileProcessor interface, thus ProcessingManager does not know which type of file it deals with, it just knows it is an IFileProcessor which implements processFile(Stream inputFile).
In the long run, you'll just have to write new FileProcessor implementations, and voila. ProcessingManager does not change over time.
Use one more method called CanHandle for example:
abstract class FileProcessor
{
public FileProcessor()
{
}
public abstract Process(string path);
public abstract bool CanHandle(string path);
}
With excel file, you can implement CanHandle as below:
class Excelprocessor: FileProcessor
{
public override void Process(string path)
{
}
public override bool CanHandle(string path)
{
return path.EndsWith(".xlsx");
}
}
In ProcessingManager, you need a list of processor which you can add in runtime by method RegisterProcessor:
class ProcessingManager
{
private List<FileProcessor> _processors;
public void RegisterProcessor(FileProcessor processor)
{
_processors.Add(processor)
}
....
So LINQ can be used in here to find appropriate processor:
while(some_condition)
{
string fPath= _this.m_list.Dequeue();
var proccessor = _processors.SingleOrDefault(p => p.CanHandle(fPath));
if (proccessor != null)
proccessor.Process(proccessor);
}
If you want to add more processor, just define and add it into ProcessingManager by using
RegisterProcessor method. You also don't change any code from other classes even FileProcessorFactory like #Highmastdon's answer.
You could use the Factory pattern (a good choice)
In Factory pattern there is the possibility not to change the existing code (Follow SOLID Principle).
In future if a new Doc file support is to be added, you could use the concept of Dictionaries. (instead of modifying the switch statement)
//Some Abstract Code to get you started (Its 2 am... not a good time to give a working code)
1. Define a new dictionary with {FileType, IFileProcessor)
2. Add to the dictionary the available classes.
3. Tomorrow if you come across a new requirement simply do this.
Dictionary.Add(FileType.Docx, new DocFileProcessor());
4. Tryparse an enum for a userinput value.
5. Get the enum instance and then get that object that does your work!
Otherwise an option: It is better to go with MEF (Managed Extensibility Framework!)
That way, you dynamically discover the classes.
For example if the support for .doc needs to be implemented you could use something like below:
Export[typeof(IFileProcessor)]
class DocFileProcessor : IFileProcessor
{
DocFileProcessor(FileType type);
/// Implement the functionality if Document type is .docx in processFile() here
}
Advantages of this method:
Your DocFileProcessor class is identified automatically since it implements IFileProcessor
Application is always Extensible. (You do an importOnce of all parts, get the matching parts and Execute.. Its that simple!)
I have a project with two class libraries.
I need to switch between them programatically, with application parameters, something like
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
// my code here
}
}
If you want to build loose-couple application, i suggest you read more about Dependancy Injection pattern.
This is a nice article, desscribed how to build such design. (First 4 lessons)
This is quite a complex requirement and you'll have to bring together multiple patterns & practices to get through this. I'll try and link off to the relevant principles as I go along.
The first problem to tackle is aligning the two class libraries such that they have a common interface. This is necessary in order to make them interchangeable as you describe. Usually this would be as simple as creating an interface that both objects implement - but you mentioned that you only have control over one of the libraries. In that case you need to utilize the adapter pattern to coerce the library you don't have control over to implement your common interface.
Say we currently have these two classes in Library1.dll and Library2.dll (Library1.dll is the one we have control over)...
// in Library1.dll
public class Foo
{
public int DoSomething() { ... }
}
// In Library2.dll
public class Foo
{
public int DoSomething() { ... }
}
First we need to define our common interface. This should reside in a core/shared library...
// In Shared.dll
public interface IFoo
{
int DoSomething();
}
Now because we have control over library one, we can easily make it implement the common interface in the usual way...
// In Library1.dll
public class Foo : IFoo
{
public int DoSomething() { ... }
}
However because we don't have control over Library2.dll we'll need to create an adapter class. The purpose of this class is simply to implement the common interface, and all behaviour is delegated to the real Library2.Foo. In effect this allows us to make the Library2.Foo object implement our common interface.
// In Shared.dll
public class Foo2Adapter : IFoo()
{
private Library2.Foo _realFoo;
public Foo2Adapter()
{
_realFoo= new Library2.Foo();
}
public int DoSomething()
{
_realFoo.DoSomething();
}
}
Now we need to modify all of our client code to use the common interface rather than the objects directly. Where before you might have had something like this...
if(arg == "a")
using LibraryA;
if(arg == "b")
using LibraryB;
namespace Project
{
public class MyClass
{
public void Bar()
{
var foo = new Foo();
foo.DoSomething();
}
}
}
Now your code should only use the interface...
namespace Project
{
public class MyClass
{
public void Bar(IFoo foo)
{
foo.DoSomething();
}
}
}
Now we have a new problem, how do we know which version of IFoo to use? Is it Library1.Foo, or Shared.Foo2Wrapper?
You can use dependency injection to solve this problem. An inversion of control container will provide objects for you, and you can configure it to provide different kinds of objects based on certain conditions. Here's a psuedocode example using a sytax similar to that used by StructureMap (my personal favourite IoC container)...
var container = new IocContainer();
if (arg == "a")
container.For<IFoo>().Use<Library1.Foo>();
else if (arg == "b")
container.For<IFoo>().Use<Shared.Foo2Adapter>();
var foo = container.GetInstance<IFoo>();
Now when we call GetInstance<IFoo>() the IoC container will give us back either a Library1.Foo or a Shared.Foo2Wrapper depending on how it was configured by the command line. We now need to go through all the places in our client code where we previously had new Foo() and replace it with container.GetInstance<IFoo>().
I hope that gets you moving :)
Here's an example of how you can achieve what you're after.
using System;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.Data
{
public interface IDataSource
{
string GetTitle(int id);
}
public class Database: IDataSource
{
public string GetTitle(int id)
{
string result;
//logic to connect to a database and retrieve a value would go here
switch (id)
{
case 1: result = "DB First Title"; break;
case 2: result = "DB Second Title"; break;
default: throw new KeyNotFoundException(string.Format("ID '{0}' not found",id));
}
return result;
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.DataTest
{
public class DatabaseMock : IDataSource
{
public string GetTitle(int id)
{
string result;
switch (id)
{
case 1: result = "DBMock First Title"; break;
case 2: result = "DBMock Second Title"; break;
default: throw new KeyNotFoundException(string.Format("ID '{0}' not found", id));
}
return result;
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
namespace StackOverflowDemo.Applications.TestFrameworkDemo.Logic
{
public class SomeBusinessObject
{
private IDataSource myData;
public SomeBusinessObject(IDataSource myData)
{
this.myData = myData;
}
public void OutputTitle(int id)
{
Console.WriteLine(myData.GetTitle(id));
}
}
}
using System;
using StackOverflowDemo.Applications.TestFrameworkDemo.Data;
//using StackOverflowDemo.Applications.TestFrameworkDemo.DataTest; //we don't need the using statement if we use the whole path below, which I think relates to your question
using StackOverflowDemo.Applications.TestFrameworkDemo.Logic;
namespace StackOverflowDemo.Applications.TestFrameworkDemo
{
class Program
{
public static void Main(string[] args)
{
IDataSource myData;
#if(DEBUG)
myData = new StackOverflowDemo.Applications.TestFrameworkDemo.DataTest.DatabaseMock();
#else
myData = new Database();
#endif
SomeBusinessObject sbo = new SomeBusinessObject(myData);
sbo.OutputTitle(1);
Console.WriteLine("Done");
Console.ReadKey();
}
}
}
More info on mocks is available here: http://msdn.microsoft.com/en-us/library/ff650441.aspx
There's also a load of stuff at Channel9: http://channel9.msdn.com/search?term=test+driven+development
Alternatively you may be interested in this: http://msdn.microsoft.com/en-us/library/hh549175(v=vs.110).aspx. It allows you to hijack methods of existing objects and replace them with dummy methods. I've not yet played with this, but it looks promising.
I am trying to learn Unity Interceptors and I am having a hard go of it.
Say I have an interface like this:
public interface IMyInterface
{
void SomeMethod();
}
And I have an unknown number of classes that implement that interface like this:
public class SpecificClass1 : IMyInterface
{
public void SomeMethod()
{
Console.WriteLine("Method Called");
}
}
I am looking for a way to say, "for all instance of IMyInterface (I don't want to enumerate them), when SomeMethod is called run my interceptor.
It is the Non-Enumeration of the classe that is giving me trouble. (There are plenty of examples if you can enumerate all your classes.)
I have read of Type Interception, but I can't seem to find out if it will do what I am looking for.
Any Unity experts out there know how to do what I am looking for?
You could create InterceptionBehavior then register it on specific class. Note you could filter executing methods in Invoke thru IMethodInvocation input
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
using NUnit.Framework;
namespace UnitTests
{
[TestFixture]
public class ForTest
{
[Test]
public void Test()
{
IUnityContainer container = new UnityContainer().AddNewExtension<Interception>();
container.RegisterType<IMyInterface, SpecificClass1>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<MyInterceptionBehavior>());
var myInterface = container.Resolve<IMyInterface>();
myInterface.SomeMethod();
}
}
public interface IMyInterface
{
void SomeMethod();
}
public class SpecificClass1 : IMyInterface
{
#region IMyInterface
public void SomeMethod()
{
Console.WriteLine("Method Called");
}
#endregion
}
public class MyInterceptionBehavior : IInterceptionBehavior
{
public bool WillExecute
{
get { return true; }
}
#region IInterceptionBehavior
public IEnumerable<Type> GetRequiredInterfaces()
{
return Enumerable.Empty<Type>();
}
public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
{
IMethodReturn result = getNext()(input, getNext);
Console.WriteLine("Interception Called");
return result;
}
#endregion
}
}
Console output
Method Called
Interception Called
More about Interception with Unity
#GSerjo, has outlined the Unity interception approach which works well. If you wanted to automate the configuration of interception you can use a UnityContainerExtension to automatically wire up all the interface interception as well as the behaviors. If you wanted to get into more specific interception (method names, signatures, return values etc.) then you would probably need to look at Policy Injection (using matching rules with CallHandlers).
So in this case the container extension would look like:
public class UnityInterfaceInterceptionRegisterer : UnityContainerExtension
{
private List<Type> interfaces = new List<Type>();
private List<IInterceptionBehavior> behaviors =
new List<IInterceptionBehavior>();
public UnityInterfaceInterceptionRegisterer(Type interfaceType,
IInterceptionBehavior interceptionBehavior)
{
interfaces.Add(interfaceType);
behaviors.Add(interceptionBehavior);
}
public UnityInterfaceInterceptionRegisterer(Type[] interfaces,
IInterceptionBehavior[] interceptionBehaviors)
{
this.interfaces.AddRange(interfaces);
this.behaviors.AddRange(interceptionBehaviors);
ValidateInterfaces(this.interfaces);
}
protected override void Initialize()
{
base.Container.AddNewExtension<Interception>();
base.Context.Registering +=
new EventHandler<RegisterEventArgs>(this.OnRegister);
}
private void ValidateInterfaces(List<Type> interfaces)
{
interfaces.ForEach((i) =>
{
if (!i.IsInterface)
throw new ArgumentException("Only interface types may be configured for interface interceptors");
}
);
}
private bool ShouldIntercept(RegisterEventArgs e)
{
return e != null && e.TypeFrom != null &&
e.TypeFrom.IsInterface && interfaces.Contains(e.TypeFrom);
}
private void OnRegister(object sender, RegisterEventArgs e)
{
if (ShouldIntercept(e))
{
IUnityContainer container = sender as IUnityContainer;
var i = new Interceptor<InterfaceInterceptor>();
i.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);
behaviors.ForEach( (b) =>
{
var ib = new InterceptionBehavior(b);
ib.AddPolicies(e.TypeFrom, e.TypeTo, e.Name, Context.Policies);
}
);
}
}
}
Then you could use it like so:
IUnityContainer container = new UnityContainer()
.AddExtension(new UnityInterfaceInterceptionRegisterer(
new Type[] { typeof(IMyInterface),
typeof(IMyOtherInterface) },
new IInterceptionBehavior[] { new MyInterceptionBehavior(),
new AnotherInterceptionBehavior() }
));
container.RegisterType<IMyInterface, SpecificClass1>();
var myInterface = container.Resolve<IMyInterface>();
myInterface.SomeMethod();
Now when the interface is registered the appropriate interception policies will also be added to the container. So in this case if the interface registered is of type IMyInterface or IMyOtherInterface then policies will be setup for interface interception and the Interception Behaviors MyInterceptionBehavior and AnotherInterceptionBehavior will also be added.
Note that Unity 3 (released after this question/answer) added a Registration by Convention feature that can do what this extension does (without having to write any custom code). An example from the Developer's Guide to Dependency Injection Using Unity:
var container = new UnityContainer();
container.AddNewExtension<Interception>();
container.RegisterTypes(
AllClasses.FromLoadedAssemblies().Where(
t => t.Namespace == "OtherUnitySamples"),
WithMappings.MatchingInterface,
getInjectionMembers: t => new InjectionMember[]
{
new Interceptor<VirtualMethodInterceptor>(),
new InterceptionBehavior<LoggingInterceptionBehavior>()
});
Setting up interception requires multiple actions incl. configuration of intercepted types, policies and handlers.
First see Using Interception in Applications for general details about the types of situations where interception is supported (with or without a DI container for example). Then see Type Interception for more details about the supported type interceptors. Especially take note of what interceptors can be used with the type of your class (otherwise the handlers will never trigger).
When you have decided what interceptor to use, configure it and create a sufficient call handler as per the links above. If you still have trouble at this point, post a more detailed question. If you have already done this, please post the configs and code as "non-enumeration of the classe" simply does not give any hints what you are actually asking. Do you by any chance mean with "enumeration" that you assign a attribute-driven policy and are unable to achieve what you want without it?
First, the simple question.
Is it possible to receive an event when MEF (System.ComponentModel.Composition) creates an instance of a part?
When this occurs I want to reflect over the created object and wire up various attributes. In Spring.Net this is possible with the IObjectPostProcessor interface.
The background is that I trying to implement Publisher/Subscriber pattern in MEF. Basically the subscriber class does this:
class MyContoller
{
[Command("Print")]
public void Print() { ... }
[Command("PrintPreview")]
public void PrintPreview() { ... }
}
And I want to detect when MyController is instantiated and wire up any methods that have the CommandAttribute.
A publisher, such as a menu item, would do Command.Get("Print").Fire() to publish the aforementioned event.
Second Question
Maybe there is an alternative pattern in MEF that I am missing!!!
I've seen some postings about MEF, Prism and the Event Aggregate, but it appears fairly complex.
FYI
Just for reference, here's the original for Spring.Net implementation:
class CommandAttributeProcessor : IObjectPostProcessor
{
static ILog log = LogManager.GetLogger(typeof(CommandAttributeProcessor));
public object PostProcessAfterInitialization(object instance, string objectName)
{
foreach (MethodInfo methodInfo in instance.GetType().GetMethods())
{
foreach (CommandAttribute attr in methodInfo.GetCustomAttributes(typeof(CommandAttribute), true))
{
if (log.IsDebugEnabled)
log.Debug(String.Format("Binding method '{0}.{1}' to command '{2}'.", instance.GetType().Name, methodInfo.Name, attr.CommandName));
Command command = Command.Get(attr.CommandName);
command.Execute += (EventHandler) Delegate.CreateDelegate(typeof(EventHandler), instance, methodInfo);
}
}
return instance;
}
public object PostProcessBeforeInitialization(object instance, string name)
{
return instance;
}
}
This may not help, but the part itself can receive notification when it is fully composed:
Automatically call method after part has been composed in MEF
Also, you probably already know this (and it might not really be related to what you are trying to do), but you can decorate your Exports and Imports such the concrete implementations are named. So, you could have an exported class something like this:
[Export("Print", typeof(IPlugin))]
[PartCreationPolicy(CreationPolicy.Shared)]
class Print : IPlugin
{
.
.
.
public Fire()
{
//Do something;
}
}
class PrintMenuItem
{
IPlugin _plugin;
[ImportingConstructor]
PrintMenuItem([Import("Print", typeof(IPlugin)] plugin)
{
_plugin = plugin;
}
void Execute()
{
_plugin.Fire();
}
}
You can use InterceptingCatalog from MEF Contrib (MEF Contrib on codeplex or you can install it by nuGet) and implement IExportedValueInterceptor interface to wire up methods that have CommandAttribute:
//using System.ComponentModel.Composition;
//using System.ComponentModel.Composition.Hosting;
//using MefContrib.Hosting.Interception;
//using MefContrib.Hosting.Interception.Configuration;
public class CommandAttributeProcessor : IExportedValueInterceptor
{
public object Intercept(object value)
{
foreach (MethodInfo methodInfo in value.GetType().GetMethods())
{
foreach (CommandAttribute attr in methodInfo.GetCustomAttributes(typeof(CommandAttribute), true))
{
// do something with command attribute
}
}
return value;
}
}
and at creating MEF catalog, you need to add interception configuration with your interceptor (CommandAttributeProcessor) and wrap your catalog in InterceptingCatalog like this:
InterceptionConfiguration interceptionConfiguration = new InterceptionConfiguration();
interceptionConfiguration.AddInterceptor(new CommandAttributeProcessor());
InterceptingCatalog interceptingCatalog = new InterceptingCatalog(assemblyCatalog, interceptionConfiguration);
CompositionContainer container = new CompositionContainer(interceptingCatalog);
Consider the following code sample that uses MEF to create an object of type Importer that imports an object of type ImporterExporter which in turn imports an object of type Exporter, i.e. Importer -> ImporterExporter -> Exporter. The catalog is managed by a CompositionUtility (obviously simplified for this example).
I know that MEF will resolve imports recursively on imported parts. However, because I want to have the option to instantiate each of these classes independetly, every class with imports also composes itself in its constructor to resolve those imports.
using System;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
namespace MefRecursionSample
{
class Program
{
static void Main(string[] args)
{
// var importerExporter = new ImporterExporter(); // include this and composition will work
var importer = new Importer();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
class CompositionUtility
{
static CompositionUtility()
{
var executingAssembly = Assembly.GetExecutingAssembly();
var assemblyCatalog = new AssemblyCatalog(executingAssembly);
_compositionContainer = new CompositionContainer(assemblyCatalog);
}
private static CompositionContainer _compositionContainer;
private static bool _isComposing;
public static void Compose(object part)
{
_compositionContainer.ComposeParts(part);
}
}
class Importer
{
public Importer()
{
CompositionUtility.Compose(this);
}
[Import]
public ImporterExporter ImporterExporter { get; set; }
}
[Export]
class ImporterExporter
{
public ImporterExporter()
{
CompositionUtility.Compose(this);
}
[Import]
public Exporter Exporter { get; set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
}
Running the code as is leads to a composition error "The ComposablePart of type MefRecursionSample.Importer' cannot be recomposed....", obviously because I am trying to explictly compose something that MEF also wants to compose.
What surprised me, was the fact that when I included the first line of the Main method, i.e. create an object of type ImporterExporter without MEF, this "double-composition" no longer caused an exception. Why is that?
Also, how could I make it work such that I could instantiate each of these indepennetly, yet also make them compose themselves when chained as in the sample. I figured I would introduce a boolean flag _compositionInProgress on the CompositionUtility and immediately return from Compose() when the flag is set to avoid the recursive composition. Is there a better way?
The flag I considered setting in the CompositionUtility's Compose method does not work, because there can be cases where the string of automatic imports is interrupted. For instance, in the question's example if Exporter instantiated a class in its constructor using new and this class would want to compose itself. Under the original solution, that class' call to Ccompose would return immediately, leaving the class uncomposed.
Because I want classes to compose themselves (thus making it unneccessary for their users to even know about MEF), the only solution was to establish the rule that classes with an [Export] attribute must not call Compose(this). Because they will be composed automatically by MEF when being imported, this would result in "double composition" and thus throw an exception.
If it is a requirement that classes marked with [Export] have to instantiated independently via new instead of nly imported via MEF, they have to have an addional constructor with a boolean flag which when set well trigger composition of that class. The default behavior, however, has to be no composition in order to avoid the aforementioned "double composition".
why not simply do this?
class Program
{
private static CompositionContainer _compositionContainer;
static void Main(string[] args)
{
//compose the container just one time in your app
var assemblyCatalog = new AssemblyCatalog(Assembly.GetExecutingAssembly());
_compositionContainer = new CompositionContainer(assemblyCatalog);
var importer = _compositionContainer.GetExportedValue<Importer>();
Console.Write(importer.ImporterExporter.Exporter.Value); // should print 7
Console.ReadKey();
}
}
[Export]
class Importer
{
[ImportingConstructor]
public Importer(ImporterExporter imex)
{
this.ImporterExporter = imex;
}
public ImporterExporter ImporterExporter { get; private set; }
}
[Export]
class ImporterExporter
{
[ImportingConstructor]
public ImporterExporter(Exporter exporter)
{
this.Exporter = exporter;
}
public Exporter Exporter { get; private set; }
}
[Export]
class Exporter
{
public int Value { get { return 7; } }
}
What you really want to do (I think) is calling container.SatisfyImportsOnce() on an object and not ComposeParts .
ComposeParts adds all exports tree to the catalog while SatisfyImportsOnce each object is to itself , composing parts and thats it , no registeration of recursive exports , so you can call constructor or use importing constructor , you can have both.
James.