Create instances with changing class names - c#

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.

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)

Passing an Action<interface> to to be executed against list of concrete implementations

So I have this
public interface ITask
{
void PrintName(string props);
void PrintState();
}
public class Epic: ITask
{
public Epic() { }
public void PrintName(string props)
{
Console.WriteLine("Hello Epic: " + props);
}
public void PrintState(string props)
{
Console.WriteLine("Epic Started");
}
}
public class Story: ITask
{
public Story() { }
public void PrintName(string props)
{
Console.WriteLine("Hello Story: " + props);
}
public void PrintState(string props)
{
Console.WriteLine("Story Started");
}
}
public class TaskProxy : ITask
{
List<ITask> list;
public TaskProxy (List<ITask> list)
{
this.list = list;
}
public void PrintName(string props)
{
foreach(ITask tsk in list)
{
tsk.PrintName(props);
}
}
public void PrintState()
{
foreach(ITask tsk in list)
{
tsk.PrintState();
}
}
}
which I am executing as
class Program
{
static List<ITask> list = new List<ITask>();
static void Main(string[] args)
{
list.Add(new Story());
list.Add(new Epic());
ITask task = TaskProxy(list );
task.PrintName("some props")
task.PrintState()
}
}
But I want this instead to be re-written as Action<> generic which will execute all similar methods in the context of a different Implementation. (something like method borrowing?)
public class TaskProxy : ITask
{
List<ITask> list;
public TaskProxy (List<ITask> list)
{
this.list = list;
}
public void PrintName(string props)
{
Generic(ITask.PrintName(props)) // looking for something like this
}
public void PrintState()
{
Generic(ITask.PrintState()) // looking for something like this
}
public void Generic(Action methodToExecute)
{
foreach(ITask tsk in list)
{
tsk.methodToExecute();
}
}
}
A generic variant could look like this:
public void Generic(Action<ITask> iTaskMethodToExecute)
{
foreach(ITask tsk in list)
{
iTaskMethodToExecute(tsk);
}
}
Explanation: Action<ITask> stands for an action that takes an ITask as parameter. This allows you to access in a lambda expression all the methods that ITask provides.
You would call it then like this:
List<ITask> list = new List<ITask>();
list.Add(new Story());
list.Add(new Epic());
TaskProxy task = new TaskProxy(list );
task.Generic(x => x.PrintName("some props"));
task.Generic(x => x.PrintState());
On the first glance it might look a little confusing to insert a ITask as parameter into the action as in this line:
iTaskMethodToExecute(tsk);
But if you look at the lambda expression call:
task.Generic(x => x.PrintState());
^
|
input of type: ITask
it should make sense because only this way the compiler is able to infer the type and intelisense will suggest even the methods in autocomplete:
For your purpose reflection would be a viable approach. The solution could look like this:
using System;
using System.Collections.Generic;
using System.Reflection;
namespace CsharpPlayground
{
public class Code
{
interface ITask
{
void printName();
}
class Story : ITask
{
public void printName()
{
Console.WriteLine("Story");
}
}
class Epic : ITask
{
public void printName()
{
Console.WriteLine("Epic");
}
}
public static void Main(string[] args)
{
var tasks = new List<ITask>
{
new Story(),
new Epic()
};
// Approach 1
Console.WriteLine("Approach 1");
foreach (var task in tasks)
{
task.printName();
}
// Approach 2
Console.WriteLine("\nApproach 2");
void GenericExecuted(MethodInfo method)
{
foreach (ITask tsk in tasks)
{
method?.Invoke(tsk, new object[0]);
}
}
var printMethod = typeof(ITask).GetMethod(nameof(ITask.printName));
GenericExecuted(printMethod);
}
}
}

Why does compiler says I'm trying to convert method from void?

I was trying how Interfaces are working but I couldn't do it. My goal is write "n" for WriteNorM() in writeN class and write "m" for WriteNorM() in writeM class. But when I try it it's saying that "you are trying to convert void into bool!" please help.(btw don't mind class names it's only a test program)
class xd
{
interface Ixd
{
void WriteNorM();
}
class writeN : Ixd
{
public void WriteNorM()
{
Console.WriteLine("n");
}
}
class writeM: Ixd
{
public void WriteNorM()
{
Console.WriteLine("m");
}
}
static void Main()
{
Ixd D = new writeN();
Ixd D1 = new writeM();
Console.WriteLine(D.WriteNorM());
Console.WriteLine(D1.WriteNorM());
}
}
Console.WriteLine expects an argument, but WriteNorM is defined as
void WriteNorM();
so it doesn't return anything, and you can't pass void to a method.
Conceptually a void method doesn't return anything, so there's no return value to pass into another method like you're trying to do:
Console.WriteLine(D.WriteNorM()); // is the same as Console.WriteLine(void)
^^^^^^^^^^^^^
void
Changing your code to
static void Main()
{
Ixd D = new writeN();
Ixd D1 = new writeM();
D.WriteNorM();
D1.WriteNorM();
}
will produce the output you want:
n
m
Alternatively, you could change your interface to have
string GetNorM();
instead (i.e. GetNorM now returns a string that you can then pass into Console.WriteLine, instead of void):
class xd
{
interface Ixd
{
string GetNorM();
}
class writeN : Ixd
{
public string GetNorM()
{
return "n";
}
}
class writeM: Ixd
{
public string GetNorM()
{
return "m";
}
}
static void Main()
{
Ixd D = new writeN();
Ixd D1 = new writeM();
Console.WriteLine(D.GetNorM());
Console.WriteLine(D1.GetNorM());
}
}

Affect an ICollection that is passed to a method as a parameter?

I have a class that has an ICollection property that is assigned by the constructor when the class is instantiated, but I want to bind this property to the original collection so that when it's updated/changed, the original list is as well. What is the best method of doing this?
Here's an example:
public class Organizations
{
private ICollection<Organization> _orgs;
public Organizations(ICollection<Organization> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add(new Organization {Name = "Testing 123"});
}
}
// in another class
public ActionResult TestApi()
{
var tmp = new SyncTool.Core.Extensions.Zendesk.Organizations(ZendeskCache.Organizations.Data);
var zd = ZendeskCache.Organizations.Data.FirstOrDefault(n => n.Name.Contains("Testing 123"));
//ZendeskCache.Org.... is a List<Organization>
return Json(new {data = "tmp" }, AG);
}
The List<Organization> you are passing to the constructor is a reference object. This code works the way you want it to (aside from syntax errors), have you tried it out?
To reproduce more simply:
public class Program
{
public static void Main(string[] args)
{
var orgs = new List<string>();
var orgClass = new Organizations(orgs);
orgClass.TestAdd();
Console.WriteLine(orgs.First());
Console.Read();
}
}
public class Organizations
{
private ICollection<string> _orgs;
public Organizations(ICollection<string> orgs)
{
_orgs = orgs;
}
public void TestAdd()
{
_orgs.Add("Testing 123");
}
}
//Output: "Testing 123"

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();
}

Categories

Resources