I`m building a simple app using MEF to better understand it, and I'm facing a problem. The app is a simple calculator that you can create new operations. Each operation is a class that exports IOperation. Here's the ADD operation class:
[Export(typeof(IOperation))]
internal class Add : IOperation
{
CompositionContainer _container;
public string Name
{
get { return "Add"; }
}
public string Symbol
{
get { return "+"; }
}
public IOperand Compute(params IOperand[] operands)
{
IOperand result = _container.GetExportedValue<IOperand>();
result.Value = operands.Sum(e => e.Value);
return result;
}
}
(IOperand is a interface that only exposes a double. The reason for it is that in version 2 you can have a expression like "(2+2)*4")
My problem as you can see is that _container
is null when I hit Compute
. This concrete class is created when the container composes a [ImportMany(typeof(IOperation))]
. So my question is: Is there a way to tell the container who is inverting control to pass a reference of himself to this object?
PS:I would not like to make _container
a public property.
Edit1: Here is the only implementation of IOperand so far:
[Export(typeof(IOperand))]
public class SimpleResult : IOperand
{
private double _value;
public double Value
{
get
{
return _value;
}
set
{
_value = value;
}
}
}
This is the "Main", where composition happens:
public class Calculator
{
[ImportMany(typeof(IOperation))]
private List<IOperation> _knownOperations;
private List<ICalculatorButton> _buttons;
private CompositionContainer _container;
public Calculator()
{
_container = new CompositionContainer(new AssemblyCatalog(Assembly.GetExecutingAssembly()));
_container.SatisfyImportsOnce(this);
_buttons = new List<ICalculatorButton>();
ICalculatorButton button;
for (int i = 0; i < 10; i++)
{
button = _container.GetExportedValue<IDigitButton>();
button.Symbol = i.ToString();
((IDigitButton)button).Value = i;
_buttons.Add(button);
}
foreach (IOperation op in _knownOperations)
{
button = _container.GetExportedValue<IOperationButton>();
button.Symbol = op.Symbol;
((IOperationButton)button).Operation = op;
_buttons.Add(button);
}
}
public IReadOnlyList<IOperation> KnownOperations
{
get { return _knownOperations.AsReadOnly(); }
}
public IReadOnlyList<ICalculatorButton> Buttons
{
get { return _buttons.AsReadOnly(); }
}
public IOperand Calculate(IOperation operation, params IOperand[] operands)
{
IOperand result = operation.Compute(operands);
return result;
}
public IOperand Calculate(IOperation operation, params double[] operands)
{
List<IOperand> res = new List<IOperand>();
foreach (double item in operands)
{
IOperand aux = _container.GetExportedValue<IOperand>();
aux.Value = item;
res.Add(aux);
}
return Calculate(operation, res.ToArray());
}
}