Generic type within Action? - c#

Action construct is generic but can that support generic type inside it?
The code snippet shown below is what I'm trying to achieve.
I'm aware of that there are other ways to do it but I am curious whether it can be achieved within an Action construct.
void SomeMethod()
{
Action<int> Initialize = //<T> and where T is all that stuff
(index) =>
{
T obj = new T();
obj.Initialize(index);
obj.DoWork();
};
Initialize<TypeA>(1);
Initialize<TypeB>(2);
}

No, basically - or at least, not within a single instance of an Action - a single instance is inherently closed in terms of generics. Obviously you could use a regular generic method Initialize<T>. If you need a single Action, then it might need to take the type as a parameter:
Action<Type, int> init = (type, index) => {
ISomeInterface obj = (ISomeInterface)Activator.CreateInstance(type);
obj.Initialize();
obj.DoWork();
};
init(typeof(TypeA), 1);
init(typeof(TypeB), 2);
Otherwise:
void Initialize<T>(int index) where T : new(), ISomeInterface {
T obj = new T();
obj.Initialize();
obj.DoWork();
}
void SomeMethod() {
Initialize<TypeA>(1);
Initialize<TypeB>(2);
}
You can create Action<int> delegates to represent separately Initialize<TypeA>(int) and Initialize<TypeB>(int), but not both at the same time, and not the open Initialize<T>(int).

Related

Choose interface child by some property

I have an interface:
public interface IPath
{
// Some method
}
and I have two classes which are inheriting this interface
public class First : IPath { }
public class Second: IPath { }
By the way, in some method I need to choose which class to use, First or Second, it depending on one string property (type), which I get from database. It looks like:
public void SomeMethod(string type)
{
if (type == "First") { // creating instance of First class }
else if (type == "Second") { // creating instance of Second class }
else { ... }
}
Question is: how can I avoid if/else or switch/case constructions and automaticly create the right instance, depending on the string variable?
You could create a dictionary to map from string to Type and the use that Type and Activator.CreateInstance to create an instance of that type.
Alternatively you could fetch the type using reflection and not need a dictionary at all
private Dictionary<string, Type> _iPathMapping = new Dictionary<string, Type>
{
{ nameof(First), typeof(First) },
{ nameof(Second), typeof(Second) },
};
// ...
public IPath Create(string path)
{
var type = _iPathMapping[path];
return (IPath) Activator.CreateInstance(type);
}
(You'd want to extend that code with safety checks, see below)
But this is fundamentally a bad solve. The problem to this is that it's harder to pass parameters to constructors and it's unsafe as well, if any of your implementations don't have a parameterless constructor, this will fail, but not with a compiler error, no it will fail during runtime, i.e once a user (or hopefully testers/ automatic tests) ran into the problem. So a better way would be to store a method that's invoked to construct the type instead of using Activator.CreateInstance, something like
private Dictionary<string, Func<IPath>> _iPathMapping = new Dictionary<string, Func<IPath>>
{
{ nameof(First), () => new First() },
{ nameof(Second), () => new Second() },
};
// ...
public IPath Create(string path)
{
if (_iPathMapping.TryGetValue(path, out var func))
return func.Invoke();
return null;
}
This solves the problem of parameters for the constructor in that it doesn't throw a runtime exception.
But we still haven't solved the problem of actually passing parameters to the constructor, especially when First and Second require different parameters. The only clean* way to I can think of to handle this in a generic and reusable way is using a Dependency Injection framework/ context to actually construct our instances.
But in general, the if/ else if chain or switch statement isn't necessarily a bad thing, you even see it in some places inside .NET
* You could replicate the part of a DI framework that's responsible for resolving dependencies for a constructor, but that's just re-implementing the wheel and might as well save the effort needed and just pull in a dependency like Microsoft.Extensions.DependencyInjection
I have a shorter version as answer, but I saw "MindSwipe" already offered you one:
Dictionary<string, Type> map = new Dictionary<string, Type>();
map.Add("First", typeof(First));
map.Add("Second", typeof(Second));
var instance = Activator.CreateInstance(map[<your parameter as string>]);

Keep a dictionary of methods with unknown signature to be invoked with reflection

I want to have a dictionary which uses strings as keys and something that represents methods, all of which may have different signatures, as values. From this something, I should be able to access a MethodInfo and an instance of an object if the method is not static, such that later on I can find it by name and invoke it using reflection.
I thought Delegate would do, but I cannot find a way to cast a static or instance method into a Delegate. I could also create my own class or structure that holds an object and a MethodInfo, but if so, my class' users would have to get a MethodInfo off of whatever method he wants to add to my dictionary and would need to add a reference to Reflection everywhere (instead of perhaps just passing the method itself or something like (Delegate)myMethod). Is there a way to do this?
If you don't mind specifying a delegate type each time you add to the dictionary, then you can use Delegate:
void A() {}
string B(string arg) { return arg; }
void Test()
{
var dict = new Dictionary<string, Delegate>();
dict.Add("A", new Action(A));
dict.Add("B", new Func<string, string>(B));
}
Sounds like you just want to have a Dictionary<string, Action> which you can wire up with lambda functions:
var actions = new Dictionary<string, Action>();
actions.Add("Foo", () => Console.WriteLine("Bar!"));
Car myCar = new Car();
actions.Add("Vroom", () => myCar.Drive());
actions["Foo"](); //prints "Bar!"
actions["Vroom"](); //invokes myCar.Drive
This way all the different signatures, or object references, or static methods, or whatever are handled by the lambda and its closure semantics.
If you want to be able to pass some context or inputs to the set, you can provide an untyped context object which you can cast when you register the method. Instead of having a parameterless Action you would have an Action<object> instead:
var actions = new Dictionary<string, Action<object>>();
var JuanLuisSoldi = new Person();
actions.Add("Lunch Time", context => JuanLuisSoldi.Eat((Food)context));
Food lunch = new Apple();
actions["Lunch Time"](lunch);
There are many ways, this is one way:
public class SomeClass
{
public IDictionary<string, Action> ActionRegistry { get; set; }
public void SomeMethod()
{
// Registering an action that doesn't use reflection:
ActionRegistry.Add("SomeAction", () => { Console.WriteLine("Hello");});
// Registering an action that uses reflection
object objectInstance; = ...
Type type; = ...
string methodName; = ...
object[] arguments; =
ActionRegistry.Add("SomeAction2", () =>
{
type.GetMethod(methodName).Invoke(objectInstance, arguments);
});
// Invoking:
ActionRegistry["SomeAction2"]();
}
}
You can regard the lambda/Action as a adapters. I use similar dictionaries a lot when I reflect.

How to pass a Func<T> without knowing the scope of T?

It may not be possible, but I am hoping it is!
I have a method which has scope of a generic type, and instansiates a List<Func<GenericType>>. I then have another method which recieves a List<Func<T>>. I can't have any knowledge of T in this method.
Example Code
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs);
}
public void RecieveFuncs(List<Func<object>> funcs)
{
//Do some stuff with funcs
}
I was wishing that it would be as easy as using object in place of T and it would be as easy of that. Of course, T isn't an object, it's a Type and therefore I can't interchange them. Any suggestions or is this impossible?
You can make your method generic:
public void RecieveFuncs<T>(List<Func<T>> funcs)
{
//Do some stuff with funcs
}
To call it, you can either declare T explicitly
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs<Item>(funcs);
}
or let the type inference magic do its work and keep the call as it is:
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs); // C# automatically infers T = Item
}
If you can't make RecieveFuncs generic for some reason, you could use:
public void PassFuncs<TItem>()
where TItem:class
{
List<Func<TItem>> funcs = new List<Func<TItem>>();
RecieveFuncs(funcs);
}
public void RecieveFuncs(IEnumerable<Func<object>> funcs)
{
//Do some stuff with funcs
}
This requires a generic constraint to reference types for TItem, and needs a co-variant interface like IEnumerable<T> instead of List<T> on the receiving side. If you really want to receive a List<Func<object>> you can create a new list with List<Func<object>>(funcs).
If you know that Item is a reference type, you can use variance of each function (but not of the list):
public void PassFuncs<Item>() where Item : class
{
List<Func<Item>> funcs = new List<Func<Item>>();
var tmp = funcs.ConvertAll(func => (Func<object>)func);
RecieveFuncs(tmp);
}
This creates a new list, but uses the original functions. If that is not possible, you'll need to add an intermediate function:
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
var tmp = funcs.ConvertAll<Func<object>>(func => () => func());
RecieveFuncs(tmp);
}
You could "cast" the Func<Item> to Func<object>, like this
public delegate object Func();
public void PassFuncs<Item>()
{
List<Func<Item>> funcs = new List<Func<Item>>();
RecieveFuncs(funcs.Select<Func<Item>, Func<object>>(f => () => (object)f())
.ToList());
}
public void RecieveFuncs(List<Func<object>> funcs)
{
//Do some stuff with funcs
}
This will work both for reference and value types, although it will box for the value types. If you use only reference types, use #CodesInChaos answer.

Create Generic Type with Generic Interface at Run Time

I've been working through an issue for a couple of hours now, and I think I'm close. I'm working on an app where we could have 50-100 types that perform the same way. So instead of creating 50-100 classes, I tried to make it generic and this is what I have:
This is the base class:
public class RavenWriterBase<T> : IRavenWriter<T> where T : class, IDataEntity
And this is the interface:
public interface IRavenWriter<T>
{
int ExecutionIntervalInSeconds { get; }
void Execute(object stateInfo);
void Initialize(int executionIntervalInSeconds, Expression<Func<T, DateTime>> timeOrderByFunc);
}
And this is how I'm using it:
private static void StartWriters()
{
Assembly assembly = typeof(IDataEntity).Assembly;
List<IDataEntity> dataEntities = ReflectionUtility.GetObjectsForAnInterface<IDataEntity>(assembly);
foreach (IDataEntity dataEntity in dataEntities)
{
Type dataEntityType = dataEntity.GetType();
Type ravenWriterType = typeof(RavenWriterBase<>).MakeGenericType(dataEntityType);
Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;
// This is where I'm stuck. How do I activate this as RavenWriterBase<T>?
var ravenWriter = Activator.CreateInstance(ravenWriterType);
//ravenWriter.Initialize(60, func); // I can't do this until I cast.
// More functionality here (not part of this issue)
}
}
I'm stuck on this line from above:
var ravenWriter = Activator.CreateInstance(ravenWriterType);
This is my question:
How can I use that as RavenWriterBase or IRavenWriter? Something like:
ravenWriter.Initialize(60, func);
I think it needs to be something like this, but I need to specify a type for IRavenWriter<> and I don't know it yet:
var ravenWriter = Activator.CreateInstance(ravenWriterType) as IRavenWriter<>;
If I hover over ravenWriter, I successfully have my object:
But now I need to be able to use it in a generic way. How can I do that?
Update:
I just thought of using the dynamic keyword, and this works:
dynamic ravenWriter = Activator.CreateInstance(ravenWriterType);
ravenWriter.Initialize(60);
I cheated a bit because I realized that the Func was the same for each IDataEntity, so that wasn't necessary to pass as a parameter to Initialize(). However, at least now I can call Initialize(). But now that the Func is the same, I shouldn't need the generic interface either.
My solution would be to:
Create a non-generic interface of IRavenWriter
Make IRavenWriter<T> inherit from IRavenWriter
Keep Execute and ExecutionIntervalInSeconds in IRavenWriter
Make IRavenWriter have Func<DateTime> and use that in your writer
Move Initialize to IRavenWriter<T>
Use a factory to initialise the Func according to the type and expression:
For example:
public class MyDateTime
{
public DateTime This { get; set; }
}
public static Func<DateTime> GetFunk<T>(Expression<Func<T, DateTime>> timeOrderByFunc, T t)
{
return () => timeOrderByFunc.Compile()(t);
}
And you use:
GetFunk<MyDateTime>(x => x.This, new MyDateTime(){This = DateTime.Now});
It's not really hard to turn run-time Type into compile-time generic Type parameter. Just introduce new interface for creating/initializing your objects:
interface IRawenWriterFactory
{
object Create();
}
class RawenWriterFactory<T> : IRawenWriterFactory
{
public object Create()
{
Expression<Func<IDataEntity, DateTime>> func = x => x.CicReadTime;
var ravenWriter = new RavenWriterBase<T>();
ravenWriter.Initialize(60, func);
return ravenWriter;
}
}
Now just create RawenWriterFactory with dataEntityType just like you've created ravenWriter and use it via non-generic IRavenWriterFactory interface.
However, there could be simpler solutions if you'll change your design. E.g. if you turn Initialize method into constructor you'll be able to pass func as Activator.CreateInstance parameter and you wouldn't need to use generic interface for initialization at all.

Specifying "any subclass" in a C# type constraint rather than "one particular subclass"

If I would like to write a method that takes a variable number of "TDerived" where TDerived is any subclass of a class "Base", is there any way to do this?
The following code only works with a single specific specified subclass:
void doStuff<TDerived>(params TDerived[] args) where TDerived : Base
{
//stuff
}
ie if I have
class Super { }
class Sub0 : Super { }
class Sub1 : Super { }
then I cannot do
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
doStuff(s0, s1);
since I get "best overloaded match... has some invalid arguments".
Regardless of how the compiler handles the type constraints and variadic functions, this seems (as far as I can tell) completely type-safe. I know I could cast, but if this is type safe why not allow it?
EDIT:
Perhaps a more convincing example:
void doStuff<TDerived>(params SomeReadOnlyCollection<TDerived>[] args) where TDerived : Base
{
foreach(var list in args)
{
foreach(TDerived thing in list)
{
//stuff
}
}
}
TDerived needs to be able to resolve to a single type. In your example, the only type it could resolve to would be Super, but the compiler is not going to make that leap. You can make that leap for the compiler.
doStuff(new Super[] { s0, s1 });
doStuff<Super>(s0, s1);
Regarding your update, consider (instead of a generic method) defining a method accepting IEnumerable<ISuper>, which will support derived types because IEnumerable<T> is covariant (as of .NET 4). IEnumerable<T> is also inherently readonly and forward-only, perfect if you have a foreach loop. Full working example:
class Program
{
static void Main()
{
var sub0s = new Sub0[] { new Sub0() };
var sub1s = new List<Sub1> { new Sub1() };
doStuff(sub0s, sub1s);
}
static void doStuff(params IEnumerable<ISuper>[] args)
{
foreach (var sequence in args)
{
foreach (var obj in sequence)
{
Console.WriteLine(obj.GetType());
// you have the ability to invoke any method or access
// any property defined on ISuper
}
}
}
}
interface ISuper { }
class Super : ISuper { }
class Sub0 : Super { }
class Sub1 : Super { }
IEnumerable<T> is implemented by BCL collections since .NET 2.0, including T[], List<T>, ReadOnlyCollection<T>, HashSet<T>, etc.
In your example, you are actually telling the compiler that all arguments to doStuff must be of the same type at compile time, and that this type has to be inherited from Base. If you want to allow the arguments to be of different types, then just don't use generics:
void doStuff(params Base[] args)
{}
EDIT
The same applies with your new example - instead of a specific SomeReadOnlyCollection you can use IEnumerable, as it is covariant:
void doStuff(params IEnumerable<Base>[] args)
{
foreach (var list in args)
{
foreach (var thing in list)
{
}
}
}
Well you could most certainly change
Sub0 s0 = new Sub0();
Sub1 s1 = new Sub1();
To
Super s0 = new Sub0();
Super s1 = new Sub1();
and then it would work if Super is TDerived.
I may be misunderstanding you, but the only way to make a method take any subclass of a base class is to declare the method to take a reference to the base type.
One other alternative you could use is to simply specify the generic parameter explicitly. For example:
var s0 = new Sub0();
var s1 = new Sub1();
doStuff<Super>(s0, s1);
You should be able to apply the same principle on the case with SomeReadOnlyCollection, as long as it is covariant. For example, IEnumerable is such a collection:
static void doStuff2<TDerived>(params IEnumerable<TDerived>[] args) where TDerived : Super {
// ...
}
// ...
var l0 = new List<Sub0>();
var l1 = new List<Sub1>();
doStuff2<Super>(l0, l1);

Categories

Resources