I am developing an open ended application and I am new to MEF. I need to hide MEF totally from derived classes. So here is my scenerio.
I have a BaseAssembly
public class ListContainer
{
[ImportMany(typeof(IBase))]
public List<IBase> MyObjects { get; set; }
public void AssembleDriverComponents()
{
.... Some code to create catalogue..
//Crete the composition container
var container = new CompositionContainer(aggregateCatalog);
// Composable parts are created here i.e. the Import and Export components assembles here
container.ComposeParts(this);
}
}
[InheritedExport(typeof(IBase))]
public abstract class Base : IBase
{
private IInfoBase infoBase;
//This is something which I want to do. If I have a derived class from Base.
Then It does not need to use ImportingConstructor.
[ImportingConstructor()]
public Base(InfoBase nfoBase)
{
this.infoBase = infoBase;
}
}
[InheritedExport(typeof(IInfoBase))]
public interface IInfoBase
{
string Category { get; set; }
}
public class InfoBase : IInfoBase
{
public string Category
{
get;
set;
}
}
Other assemblies will refer to base assembly.
ReferenceAssembly will have
public class Derived : Base
{
public Derived(BaseInfo info)
: base(info)
{
info.Category = "CategoryA";
}
}
In this case MEF is not creating the object for derived one.
In summary, I need something like InheritedExport for ImportingConstructor also.
You can do this using MEF2. MEF2 introduces the Convention-Based Programming Model which can replace or complement the "Attributed Programming Model".
For the interface IBase
:
public interface IBase { }
The abstract base class Base
:
[InheritedExport(typeof(IBase))]
public abstract class Base : IBase
{
private IInfoBase infoBase;
//No ImportingConstructorAttribute. This will be set with conventions.
public Base(IInfoBase infoBase)
{
this.infoBase = infoBase;
}
}
A couple of Base
implementations:
public class Derived : Base
{
public Derived(IInfoBase info)
: base(info)
{
info.Category = "CategoryA";
}
}
public class AnotherDerived : Base
{
public AnotherDerived(IInfoBase info)
: base(info)
{
info.Category = "CategoryB";
}
}
The info interface is unchanged:
[InheritedExport(typeof(IInfoBase))]
public interface IInfoBase
{
string Category { get; set; }
}
Added the PartCreationPolicyAttribute so that the exported parts are not shared between the implementations of Base. This doesn't matter though.
[PartCreationPolicy(CreationPolicy.NonShared)]
public class InfoBase : IInfoBase
{
public string Category
{
get;
set;
}
}
And finally the ListContainer
:
public class ListContainer
{
[ImportMany(typeof(IBase))]
public List<IBase> MyObjects { get; set; }
public void AssembleDriverComponents()
{
var regBuilder = new RegistrationBuilder();
//SelectConstructor is the equivalent of the ImportingConstructorAttribute.
//Note that my approach here is very crude. Simply use the first constructor.
regBuilder.ForTypesDerivedFrom<Base>().SelectConstructor(ctors => ctors.First());
//Only an AssemblyCatalog for this example. Note that the registration
//builder is used here.
var catalog = new AssemblyCatalog(Assembly.GetExecutingAssembly(), regBuilder);
//Crete the composition container
var container = new CompositionContainer(catalog);
// Composable parts are created here i.e. the Import and Export components assembles here
container.SatisfyImportsOnce(this);
System.Diagnostics.Debug.Assert(this.MyObjects.Count == 2);
}
}
More info on MEF Conventions: MEF 2 article series and Getting started with convention-based part registration in MEF 2