MEF-Import into Dictionary - c#

Iam currently refactoring a application and want to introduce MEF.
The Export class (class Apple) is finished and marked with Export-keyword...
On the import site I currently have a dictionary which is initialized as shown below:
Dictionary<int, Apple> dict = new Dictionary<int, Apple>();
for(int i=0; i < 10; i++)
dict.add(i, new Apple());
...
How can I initialize the dictionary using MEF?

So I think your question boils down to, "How to I ensure that the container produces multiple instances of an object rather than reusing the same object every time it's requested." Well that's pretty easy–you just have to specify CreationPolicy.NonShared.
Consider this example implementation of IApple:
public interface IApple { }
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(typeof(IApple))]
public class Apple : IApple
{
private static int appleCounter = 0;
private int id;
public Apple()
{
this.id = ++appleCounter;
}
public override string ToString()
{
return "Apple #" + this.id.ToString();
}
}
Here's one way that you might use it:
class Program
{
public static void Main(string[] args)
{
var catalog = new ApplicationCatalog();
var container = new CompositionContainer(catalog);
IDictionary<int, IApple> dict = new Dictionary<int, IApple>();
for (int i = 0; i < 10; i++)
{
dict.Add(i, container.GetExportedValue<IApple>());
}
foreach (var pair in dict)
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
}
}
The key line of code here is [PartCreationPolicy(CreationPolicy.NonShared)]. Without this, the only one Apple would ever be created. Of course this isn't quite as useful as you're probably hoping for. Here's another way to generate a dictionary that's a bit more flexible:
public interface IBasket
{
IDictionary<int, IApple> GetAppleDictionary();
}
[Export(typeof(IBasket))]
public class Basket : IBasket
{
private IDictionary<int, IApple> dict;
[ImportingConstructor]
public Basket([Import] CompositionContainer container)
{
this.dict = new Dictionary<int, IApple>();
for (int i = 0; i < 10; i++)
{
this.dict.Add(i, container.GetExportedValue<IApple>());
}
}
public IDictionary<int, IApple> GetAppleDictionary()
{
return dict;
}
}
class Program
{
[Import(typeof(IBasket))]
private IBasket basket = null;
public static void Main(string[] args)
{
var program = new Program();
program.Run();
}
private void Run()
{
var catalog = new ApplicationCatalog();
var container = CreateCompositionContainer(catalog);
container.ComposeParts(this);
foreach (var pair in this.basket.GetAppleDictionary())
{
Console.WriteLine("{0}: {1}", pair.Key, pair.Value);
}
}
private static CompositionContainer CreateCompositionContainer(ComposablePartCatalog catalog)
{
var wrappedCatalog = new AggregateCatalog(catalog, new TypeCatalog(typeof (CompositionContainer)));
var container = new CompositionContainer(wrappedCatalog);
container.ComposeExportedValue(container);
return container;
}
}
The tricky part here is CreateCompositionContainer. This method ensures that the the CompositionContainer itself can be used to satisfy an import on an object it's composing. This allows the Basket to directly manipulate the container to generate all the apples it needs.
And just for the purpose of demonstration, here's one way you could also use the [ImportMany] attribute to accomplish something similar (although all those [Export]'s really make me cringe):
public interface IApple { }
[PartCreationPolicy(CreationPolicy.NonShared)]
[Export(typeof(IApple))]
[Export(typeof(IApple))]
/* ..repeat N times.. */
[Export(typeof(IApple))]
public class Apple : IApple
{
private static int appleCounter = 0;
private int id;
public Apple()
{
this.id = ++appleCounter;
}
public override string ToString()
{
return "Apple #" + this.id.ToString();
}
}
class Program
{
[ImportMany(typeof(IApple))]
private IEnumerable<IApple> apples = null;
public static void Main(string[] args)
{
var program = new Program();
program.Run();
}
void Run()
{
var catalog = new AssemblyCatalog(this.GetType().Assembly);
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
apples.Dump();
}
}

Related

Is there a way to write a generic method that fills lists of different types?

I have a parent class called Snack with subclasses Drink and Sweets. I want to store my Snacks in a "VendingMachine" Class where there is a list for each of the Products. However, I don't want to write the same method for each type of Snack. How would you write this as a generic method ?
// DRINKS LIST
List<Drink> drinks = new List<Drink>();
public List<Drink> Drinks { get => drinks; set => drinks = value; }
private void FillWithProducts <Product> (params Product[] products) where Product : Snack
{
Type typeParameter = typeof(Product);
Type drink = typeof(Drink);
foreach (Product p in products)
{
if (typeParameter.Equals(drink))
{
Drinks.Add(p);
}
}
}
If you really need to store each kinds of products in theair own list, you can use a dynamically populated dictionary where the key is the type, something like this.
private readonly Dictionary<Type, List<Product>> storeByType = new();
public List<Drink> Drinks => (List<Drink>)this.storeByType[typeof(Drink)]
private void FillWithProducts<Product>(params Product[] products) where Product : Snack
{
foreach (Product p in products)
{
var key = p.GetType();
if (!this.storeByType.ContainsKey(key)) {
// ... add new List<T> instantiated by reflection
// use MakeGenericType + Activator.CreateInstance for example
}
// cast to the non-generic interface
var list = (IList)this.storeByType[key];
list.Add(p);
}
}
Note, that the code is just present as an example to demonstrate the idea, missing many checks and safety, and might not even work as is.
I would keep a dictionary inside the VendingMachine that holds the snacks of different types with the type as the key. By doing so you avoid having to search a list with mixed types every time you want to fetch the items.
static void Main(string[] args)
{
var m = new VendingMachine();
m.AddRange(new Drink(), new Drink());
m.AddRange(new Sweet());
var drinks = m.Fetch<Drink>();
var sweets = m.Fetch<Sweet>();
}
public class VendingMachine
{
private readonly Dictionary<Type, List<Snack>> _snacks = new();
public void AddRange<T>(params T[] snacks) where T : Snack
{
var type = typeof(T);
if (_snacks.TryGetValue(type, out var existingSnacks))
existingSnacks.AddRange(snacks);
else
_snacks.Add(type, new List<Snack>(snacks));
}
public List<T> Fetch<T>() where T : Snack
{
if (_snacks.TryGetValue(typeof(T), out var existingSnacks))
return new List<T>(existingSnacks.Cast<T>());
return new List<T>();
}
}
I think maybe there's a different way of doing this. With your base SnackBase base class and derived Drink and Sweet classes, you can fill a VendingMachine class with snacks then get the drink and sweet lists from the vending machine. The code below illustrates this:
Base Class
internal class SnackBase
{
public string Name { get; }
protected SnackBase(string name)
{
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentOutOfRangeException(nameof(name));
Name = name;
}
}
Derived classes
internal class Drink : SnackBase
{
public Drink(string name) : base(name) {}
}
internal class Sweet : SnackBase
{
public Sweet(string name) : base(name) {}
}
VendingMachine.cs
internal class VendingMachine
{
private readonly List<SnackBase> _snacks;
public VendingMachine(List<SnackBase> snacks)
{
_snacks = snacks;
}
public List<SnackBase> GetDrinks()
{
return _snacks.Where(s => s.GetType().Name == nameof(Drink)).ToList();
}
public List<SnackBase> GetSweets()
{
return _snacks.Where(s => s.GetType().Name == nameof(Sweet)).ToList();
}
}
Program.cs
internal static class Program
{
public static void Main()
{
var snacks = new List<SnackBase>
{
new Drink("Coke"),
new Sweet("Snickers"),
new Drink("Pepsi"),
new Sweet("Mars Bar"),
new Drink("7 Up"),
new Sweet("Reece's Pieces")
};
var vendingMachine = new VendingMachine(snacks);
Console.WriteLine("Drinks");
Console.WriteLine("------");
var drinks = vendingMachine.GetDrinks();
foreach (var drink in drinks)
{
Console.WriteLine(drink.Name);
}
Console.WriteLine("Sweets");
Console.WriteLine("------");
var sweets = vendingMachine.GetSweets();
foreach (var sweet in sweets)
{
Console.WriteLine(sweet.Name);
}
}
}
The vending machine class only needs one list of the common type (Snack)
Snacks
public abstract class Snack
{
protected Snack(string name)
{
Name = name;
}
public string Name { get; }
public abstract override string ToString();
}
public class Sweet : Snack
{
public Sweet(string name) : base(name)
{
}
public override string ToString() => $"Sweet({Name})";
}
public class Drink : Snack
{
public Drink(string name) : base(name)
{
}
public override string ToString() => $"Drink({Name})";
}
Vending Machine
public class VendingMachine
{
readonly List<Snack> _snacks;
public VendingMachine(params Snack[] snacks) => _snacks = new List<Snack>(snacks);
public VendingMachine(IEnumerable<Snack> snacks) => _snacks = new List<Snack>(snacks);
public IReadOnlyList<Snack> Snacks { get => _snacks; }
public IReadOnlyList<Drink> Drinks { get => _snacks.OfType<Drink>().ToList(); }
public IReadOnlyList<Sweet> Sweets { get => _snacks.OfType<Sweet>().ToList(); }
public void AddDrink(string name) => _snacks.Add(new Drink(name));
public void AddSweet(string name) => _snacks.Add(new Sweet(name));
}
Test Program
static class Program
{
static void Main(string[] args)
{
var vend = new VendingMachine();
vend.AddDrink("Joke Cola");
vend.AddSweet("Mersa Bar");
vend.AddDrink("Diet Goo");
vend.AddDrink("Bronto Care");
vend.AddSweet("Broken Tooth");
Console.WriteLine("Vending Machine Sweets");
foreach (var item in vend.Sweets)
{
Console.WriteLine(item);
}
Console.WriteLine();
Console.WriteLine("Vending Machine Drinks");
foreach (var item in vend.Drinks)
{
Console.WriteLine(item);
}
}
}
Sample Output
Vending Machine Sweets
Sweet(Mersa Bar)
Sweet(Broken Tooth)
Vending Machine Drinks
Drink(Joke Cola)
Drink(Diet Goo)
Drink(Bronto Care)

Unit test singletons

I have a singleton class and I want to run some unit tests in isolation. The problem is that all the tests run on the same instance and affect the expected results. Is there a workaround? I am using .net 6 and NUnit 3. Here's my code,
public interface ISingletonModel<T>
{
void AddValue(string key, T value, LinkedListNode node);
}
public sealed class SingletonModel<T> : ISingletonModel<T>
{
public Dictionary<string, (LinkedListNode<string> node, T value)> ModelDictionary { get; set; }
private static readonly Lazy<SingletonModel<T>> singletonModel=
new Lazy<SingletonModel<T>>(() => new SingletonModel<T>());
public static SingletonModel<T> Instance
{
get
{
return SingletonModel.Value;
}
}
private SingletonModel()
{
ModelDictionary = new Dictionary<string, (node, T value)>();
}
}
public void AddValue(string key, T value, LinkedListNode node)
{
if (ModelDictionary.ContainsKey(key))
{
var linkedListNode = ModelDictionary[key];
ModelDictionary[key] = (node, value);
}
else
{
ModelDictionary.Add(key, (node.AddFirst(key), value));
}
}
}
And some unit tests
private TestClass[] testData;
private IFixture fixture;
private SingletonModel<TestClass> model;
[SetUp]
public void Setup()
{
this.testData = GenerateTestData();
this.model= SingletonModel<TestClass>.Instance;
}
[Test]
public void CheckModelCapacity_ShouldReturnTheCorrectItems()
{
/ Act
foreach (var entity in testData)
{
this.model.AddValue(entity.Id, entity, entity.node);
}
IEnumerable<string> expected = new[] { "8", "3", "5", "2", "79" };
var actual = this.model.ModelDictionary.Keys.ToList();
// Assert
Assert.That(expected.OrderBy(x => x).SequenceEqual(actual.OrderBy(x => x)));
}
[Test]
public void CheckTotalItems_ShouldReplaceItemsWithTheSameKey()
{
// Assign
var entity1 = fixture.CreateMany(20);
// Act
foreach (var item in entity1)
{
this.model.AddValue(item.Id, item, item.node);
}
//Assert
Assert.AreEqual(2, this.model.ModelDictionary.Count);
}
Because of the singleton the tests are holding the values from the previous tests.
A public or internal constructor would allow for creating isolated instances in tests, but if the intention here is to not modify the current class then reflection can be used to access the private constructor to create isolated instances for tests.
Here is a simplified model based on the original since it was incomplete and wouldn't compile.
public interface ISingletonModel<T> {
void AddValue(string key, T value);
int Count { get; }
}
public sealed class SingletonModel<T> : ISingletonModel<T> {
Dictionary<string, T> dictionary;
private static readonly Lazy<SingletonModel<T>> singletonModel = new Lazy<SingletonModel<T>>(() => new SingletonModel<T>());
public static SingletonModel<T> Instance => singletonModel.Value;
private SingletonModel() {
dictionary = new Dictionary<string, T>();
}
public void AddValue(string key, T value) => dictionary[key] = value;
public int Count => dictionary.Count;
}
Using one of the overloads of Activator.CreateInstance:
Activator.CreateInstance(Type type, bool nonPublic)
which uses reflection to access the private constructor, shows that instances can be created to be tested in isolation
public class Program {
public static void Main() {
//Arrange
int expected = 1;
ISingletonModel<int> model1 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model1.AddValue("one", 1);
//Assert
int actual = model1.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
//Arrange
expected = 3;
ISingletonModel<int> model2 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model2.AddValue("one", 1);
model2.AddValue("two", 2);
model2.AddValue("three", 3);
//Assert
actual = model2.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
//Arrange
expected = 2;
ISingletonModel<int> model3 = (ISingletonModel<int>)Activator.CreateInstance(typeof(SingletonModel<int>), true);
//Act
model3.AddValue("one", 1);
model3.AddValue("two", 2);
//Assert
actual = model3.Count;
Console.WriteLine($"{actual}, As expected: {actual == expected}");
}
}
which return the following output
1, As expected: True
3, As expected: True
2, As expected: True
Add ResetForTesting() method your singleton class?

Create instances with changing class names

I want to call many tests like this.
var test8001 = new Test8001();
test8001.Execute(drv);
var test8002 = new Test8002();
test8002.Execute(drv);
var test8007 = new Test8007();
test8007.Execute(drv);
How can I automatically instantiate all test function with a int list of all test numbers?
List<int> classNameNumbers = new List<int>() { 8001, 8002, 8007 };
I need a for-loop where Execute() is called on every instance.
Edit:
The name of the type e.g. 'Test8001' should be retrieved from my integer list.
Try out the following
namespace Stackoverflow46529447
{
class Program
{
static void Main(string[] args)
{
var drv = new Drv();
var numbers = new[] {8001, 8002, 8003};
var executables = numbers.Select(x => Activator.CreateInstance(Type.GetType($"Stackoverflow46529447.Test{x:0000}")))
.OfType<IExecutable>()
.ToArray();
foreach (var executable in executables)
{
executable.Execute(drv);
}
}
}
public class Test8001 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8001");
}
}
public class Test8002 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8002");
}
}
public class Test8003 : IExecutable
{
public void Execute(Drv drv)
{
Console.WriteLine("Hello from Test 8003");
}
}
public interface IExecutable
{
void Execute(Drv drv);
}
public class Drv
{
}
}
This uses reflection to create instance types.

Ninject InSingletonScope Creating multiple instances

I have a very simple test project where I try tell ninject that my ILoader instance should be a singleton. No matter what I do it creates multiple instances of it.
Simple interface.
public interface ILoader
{
IEnumerable<int> Get();
}
Implementation for test purpose
public class TestLoader : ILoader
{
private IEnumerable<int> _Datasource;
public void Set(IEnumerable<int> enumerable)
{
_Datasource = enumerable;
}
public IEnumerable<int> Get()
{
return _Datasource;
}
}
Class that depends on it
public class TestClass
{
private ILoader _loader;
public TestClass(ILoader loader)
{
_loader = loader;
}
public void Init()
{
foreach (var i in _loader.Get())
Console.WriteLine(i);
}
}
Module
public class TestModule : NinjectModule
{
public override void Load()
{
Bind<ILoader>().To<TestLoader>();
Bind<TestLoader>().ToSelf().InSingletonScope();
}
}
And run it.
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new TestModule());
var ds = new List<int> { 1, 2 };
kernel.Get<TestLoader>().Set(ds);
var tc = kernel.Get<TestClass>();
tc.Init();
Console.ReadLine();
}
}
Here I want to preload my loader with testdata and the ninject should inject that very same loader into my TestClass. However it creates a new instance which is not really the desired behaviour.
I guess there are ways to work around this. But then what is the purpose of InSingletonScope? Shouldnt I be able to tell ninject that I want one and only one instance of ILoader.
Instead of having the Set method, you should use constructor injection (see this question) like this:
public class TestLoader : ILoader
{
private IEnumerable<int> _Datasource;
public TestLoader(IEnumerable<int> enumerable)
{
_Datasource = enumerable;
}
public IEnumerable<int> Get()
{
return _Datasource;
}
}
And then here is how you would register it and resolve it:
static void Main(string[] args)
{
var kernel = new StandardKernel();
var ds = new List<int> { 1, 2 };
kernel
.Bind<ILoader>()
.To<TestLoader>()
.InSingletonScope()
.WithConstructorArgument("enumerable", ds);
var tc1 = kernel.Get<TestClass>();
var tc2 = kernel.Get<TestClass>();
tc1.Init();
tc2.Init();
Console.ReadLine();
}
In this example, the two instance of TestClass will get the same instance of TestLoader injected into them.
If for some reason you don't want to use constructor injection and you want to keep the Set method, you can do this:
static void Main(string[] args)
{
var kernel = new StandardKernel();
var ds = new List<int> { 1, 2 };
kernel
.Bind<ILoader>()
.To<TestLoader>()
.InSingletonScope();
((TestLoader)kernel.Get<ILoader>()).Set(ds);
var tc1 = kernel.Get<TestClass>();
var tc2 = kernel.Get<TestClass>();
tc1.Init();
tc2.Init();
Console.ReadLine();
}

Shared Data Members that are unique to inheritance branches?

I have the situation below. Is there a simple way to design this so that the data member sample is shared among all instantiations of ChildClass1 and a separate instance of it is shared with all instances of ChildClass2?
abstract class BaseClass{
int sample = 0;
}
class ChildClass1: BaseClass{
}
class ChildClass2: BaseClass{
}
I'm hoping to produce the following
ChildClass1 a = new ChildClass1();
ChildClass1 b = new ChildClass1();
ChildClass2 c = new ChildClass2();
a.sample = 10;
//a.sample = 10, b.sample = 10, c.sample = 0
Maybe this does, what you want:
public abstract class BaseClass
{
public abstract int Sample { get; set; }
}
public class ChildClass1 : BaseClass
{
private static int mSample = 0;
public override int Sample
{
get { return mSample; }
set { mSample = value; }
}
}
public class ChildClass2 : BaseClass
{
private static int mSample = 0;
public override int Sample
{
get { return mSample; }
set { mSample = value; }
}
}
class Program
{
static void Main(string[] args)
{
var a = new ChildClass1();
var b = new ChildClass1();
var c = new ChildClass2();
a.Sample = 10;
Console.WriteLine(a.Sample); // 10
Console.WriteLine(b.Sample); // 10
Console.WriteLine(c.Sample); // 0
}
}
As I said in my comment, I think there is an inherent flaw in your design, but for the sake of providing an answer, you could achieve it like this:
abstract class BaseClass<TDERIVED>
{
private static Dictionary<Type, int> sampleDictionary_ = new Dictionary<Type, int>();
public BaseClass()
{
} // eo ctor
public int Sample
{
get
{
return sampleDictionary_.ContainsKey(typeof(TDERIVED)) ? sampleDictionary_[typeof(TDERIVED)] : 0;
}
set
{
sampleDictionary_[typeof(TDERIVED)] = value;
}
}
}
class ChildClass1 : BaseClass<ChildClass1>
{
}
class ChildClass2 : BaseClass<ChildClass2>
{
}
This has the added advantage that if you add any other Child classes, they will get their own version of the response. Note that this is not thread-safe, and so if you do choose this solution and want to use it in a multi-threaded environment, you might want to put some thread-safety code in place.
You may want to look into the singleton pattern.
Create a class as a singleton to hold the shared data. Then have all three classes reference the singleton.

Categories

Resources