Here's how I would want it work
container.GetButDoNotCreate<T>(); // should throw (or can return null) if container doesn't contain an instance matching the contract
var x = container.GetExportedValue<T>();
var y = container.GetButDoNotCreate<T>(); // should return the object created in previous step
Assert.That(x).IsSameAs(y);
The difference is that this method won't create an instance if the container doesn't contain it. It is a pure-get i.e. get me this object if it exists in the container. I need it for my tests where I do not want the test code to create objects in the production container (if they are not created) just use existing ones. Only production code should add/remove objects to the container.
Posted to MEF codeplex forum but no responses. So hoping someone on SO might have an answer. Also if I'd need to write that function as an extension method... that'd be fine as an answer too.
Here is my solution. At first I tried creating an extension method. I tried several things, read the doc and explored the available properties, events and methods on the container and catalog, but I couldn't make anything work.
After thinking about the problem, the only way I can come up with a solution is to create a derived container that is based on CompositionContainer and implements the GetButDoNotCreate method.
Update: I realized after posting it that the solution only works in the simple example you have posted where only GetExportedValue is used to retrieve parts simple parts. Unless you use the container as a simple service locator for parts with no [Import]s that will not do when parts with [Import]s are created.
Here is the implementation:
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.ComponentModel.Composition.Primitives;
namespace GetButNotCreate
{
public class CustomContainer : CompositionContainer
{
private List<Type> composedTypes = new List<Type>();
public CustomContainer(ComposablePartCatalog catalog)
: base(catalog)
{
}
public new T GetExportedValue<T>()
{
if (!composedTypes.Contains(typeof(T)))
composedTypes.Add(typeof(T));
return base.GetExportedValue<T>();
}
public T GetButDoNotCreate<T>()
{
if (composedTypes.Contains(typeof(T)))
{
return base.GetExportedValue<T>();
}
throw new Exception("Type has not been composed yet.");
}
}
}
It works by overriding the GetExportedValue method to keep track of the types that have been composed thus far and then using this to check for type composition in GetButNotCreate. I throwed an exception like you mentioned in your question.
Of course, you might need to override the overloads of GetExportedValue (unless you don't use them, but even so, I would override them anyway for safety) and maybe add other constructors and stuff if you use the class. In this example, I did the minimum to get it to work.
Here are the unit tests that test the new method:
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace GetButNotCreate
{
public interface IInterface { }
[Export(typeof(IInterface))]
public class MyClass : IInterface
{
}
[TestClass]
public class UnitTest1
{
[TestMethod]
[ExpectedException(typeof(Exception), "Type has not been composed yet.")]
public void GetButNotCreate_will_throw_exception_if_type_not_composed_yet()
{
var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
CustomContainer container = new CustomContainer(catalog);
container.ComposeParts(this);
var test = container.GetButDoNotCreate<IInterface>();
}
[TestMethod]
public void GetButNotCreate_will_return_type_if_it_as_been_composed()
{
var catalog = new AssemblyCatalog(typeof(UnitTest1).Assembly);
CustomContainer container = new CustomContainer(catalog);
container.ComposeParts(this);
var x = container.GetExportedValue<IInterface>();
var y = container.GetButDoNotCreate<IInterface>();
Assert.IsNotNull(y);
Assert.AreEqual(x, y);
}
}
}
It shows that the GetButNotCreate will throw an exception if the type has never been exported and that it will return this type if it has already been imported.
I couldn't find any hooks anywhere to check (without resorting to reflection) to see if MEF has composed a part, so this CustomContainer solution would be my best bet.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With