Store multiple contravariant delegates in a dictionary - c#

I have following statement:
private delegate ITask<Id> CreateObjectDelegateAsync<in T>(T #object)
where T : Model.Object;
And I want to store that in a dictionary:
Dictionary<Type, CreateObjectDelegateAsync<Model.Object>>
Now I am getting errors since T is not covariant and he can't convert it. I have multiple delegates with a derived T that need to be inside that dictionary.
T must be invariant in order for it to be usable as a type in the parameters. Any ideas or workarounds for this?

So the solution was quite simple: While I can't do it with invariance here directly, I can just use a:
Dictionary<Type, Delegate>
instead. I can assign any delegate to that no matter the generic type. Then later when getting the delegate I will just need to cast it to
CreateObjectDelegateAsync<T>
again.
Like so (given that T is an existing type in the dictionary):
(CreateObjectDelegateAsync<T>)DelegateDictionary[typeof(T)]

Related

Aliasing a generic interface with a using alias directive

I am aware that it's not possible to alias a generic type (e.g. using Foo = Dictionary; is invalid), but that the generic type on the right must be closed (e.g. using Foo = Dictionary<int, string>; will work).
However, it seems like it's invalid to alias an IDictionary<string, object>--instead, the alias must be for just the interface IDictionary. The error I get is "CS0308: The non-generic type 'IDictionary' cannot be used with type arguments." Is there a way to alias this entire thing? (Or a better way to achieve what I want?)
A common thing I do in my API is for functions to take an IDictionary<string, object>, and I'd like to do something akin to using ParsedObjects = IDictionary<string, object>;. In fact, I'd like to be able to declare:
using ParsedObjectsHandler = Func<Interaction, object, IDictionary<string, object>, Task>;
(But I am willing to settle for just the former.)
Edit: Although the below answer solves the question (and I'm leaving it up as I could not find the info anywhere else), I did go with V.Lion's suggestion in the comments to define my own delegate type instead.
The issue was that I was attempting to use System.Collections.IDictionary instead of System.Collections.Generic.IDictionary<TKey, TValue>. Using the latter worked just fine, i.e.:
using ParsedObjects = System.Collections.Generic.IDictionary<string, object>;

Invoke a Func object using reflection and a Type that's known at runtime

I've been trying to wrap my head around handling this scenario. The various similar (but not specifically the same) questions I've browsed on SO hasn't quite led me to where I'd like.
I have a situation where I have a Type and an object of type Func<string, (bool, T)> where T matches the Type. I'd like to be able to, via reflection or other means, call its Invoke method.
I have some Type at runtime:
Type type;
I have the Func in memory, but as an object:
object func;
The underlying Type of func is what I described earlier. For example, if type represents DateTime, then func's underlying type would be:
Func<string, (bool, DateTime)>
But type can be anything at runtime, so if it was instead an int, then func would now be a
Func<string, (bool, int)>
How can I use the fact that I have the correct type at runtime, to invoke my func? I'm assuming I have to use reflection of some sort but don't really understand it well enough to get started.
Any help is greatly appreciated.
I'm pretty new to reflection in general but I'm finding it very interesting and pretty difficult for some things. If you have any recommendations on readings or any other tips on how to better learn about reflection that'd be sweet as well!
EDIT/UPDATE after some more thought:
Would it be better just to use dynamic and call Invoke that way? Seems like it would work fine, but then that raises the question, of why you would ever go through the more difficult or longer process of setting up reflection to invoke something, instead of a simply dynamic call.
In any case, I'd still like to know how this would work using reflection, would be interesting to see
The problem is wrong and "artificial". Yes, you can use reflection, yes, you can use dynamic... But the "right" thing to do would be to change the signature to:
public (bool, object) SomeMethod(string par)
delegate:
Func<string, (bool, object)>
or
public bool SomeMethod(string par, out object obj)
delegate (note that you can't use Func<,>/Action<,>):
public delegate bool MyDelegate(string par, out object obj)
With this signature you don't need reflection to call the method and you don't need reflection to parse the return. Your return value/out is boxed by the method inside the object. The performance is still better than using reflection.
Other semi-good candidate could be:
Tuple<bool, type> SomeMethod(string par)
(where type is your changing type)
delegate:
Func<string, object>
or
Func<string, dynamic>
By using a Tuple<bool, type> you gain something: Tuple<> is a reference type, and delegates are contravariant in the return type, so you can "unify" them to object/dynamic (dynamic is an object with some information to the C# compiler that the programmer will try to do "bad things" to the object)
Now you'll have to use reflection/dynamic to access the Tuple<>.Item1 and Tuple<>.Item2.
The difference between using reflection and using dynamic is that by using reflection you can "cache" by type part of the reflection, so speeding up later uses of type methods, with dynamic this doesn't happen.
If you know the type of your function like Func you can cast it directly as below
private static void InvokeFunctionDynamically<T>(T data)
{
//1. Define the delegate
Func<string, bool, T> genericFunction = (name, isEnabled) =>
{
if(isEnabled)
{
return data;
}
return default(T);
};
// 2. demonstrate that the delegate is retrieved at the run time as an object
object runtimeObject = genericFunction;
//3. Cast it directly to the delegate type
var result =((Func<string, bool, T>) runtimeObject)("hello", true);
Console.WriteLine($"Result {result}");
}
The results are below:

Convert Func<DerivedType, Object> to Func<BaseType, Object>

What is the best way to convert from a delegate that takes a first parameter of a derived type into one that receives a base type?
What I mean is:
Func<DerivedType, Object> original = ...;
Func<BaseType, Object> converted = Something(original);
Casts, of course, do not work, since these are actually two different types.
Since you want to pass a base type to a method that takes a derived type, you need to add a cast. If you know that all calls to converted would be passing DerivedType, you could make a straightforward wrapper, like this:
Func<BaseType,Object> converted = b => original((DerivedType)b);
Demo.

C# -- Knowing a base type of a Generic Type

How can I find out the base type of a generic type?
For example
Func<A, B>
I'd like to be able to say this is a Func<> .. but apparently, Func<,> is different from Func<> -- Is there a way to somehow catch them both, or Func<,,,> etc?
You're looking for GetGenericTypeDefinition:
var t = typeof(Func<int, string>);
var tGeneric = t.GetGenericTypeDefinition();
Assert.AreEqual(typeof(Func<,>), tGeneric);
If you then want to know if a type is one of the many Func<> variants, then your best best is simply to do something like this. Checking type names, as suggested elsewhere is absolutely NOT the way to check type identity:
static Type[] funcGenerics = new[]{
typeof(Func<>), typeof(Func<,>), typeof(Func<,,>), typeof(Func<,,,>),
/* and so on... */
}
//there are other ways to do the above - but this is the most explicit.
static bool IsFuncType(Type t)
{
if(t.IsGenericTypeDefinition)
return funcGenerics.Any(tt => tt == t);
else if(t.IsGenericType)
return IsFuncType(t.GetGenericTypeDefinition());
return false;
}
Your terminology is incorrect - which I suspect why you got a downvote on your question. A base type is one that a type inherits from (not an interface, which is different, although conceptually very similar).
A generic type definition is best thought of as being like a template (the strong qualification there because the term 'template' is used in C++ and, while visually similar they are very different in implementation).
More accurately, Func<,> is a generic type definition whereas Func<int, string> is a closed generic (the 'generic type').
You can also have an open generic, which is where the type arguments are generic parameters - e.g, given:
class MyType<T> : List<T> { }
Then List<T> is an open generic with the generic type definition List<>, because T is a generic parameter which will not be closed till MyType<T> is referenced with a concrete type argument, such as int or string.
Finally, just because a bunch of generic types share the same common name, e.g. Func<>, Func<,>, and Func<,,> it does not mean they are in any way related. At the type level, there is no explicit connection, which is why you have to check for all these type identities, and why there is no common 'base' as you put it. If they all had a common interface or base class, however, then you could - by checking for compatibility with that interface or base type.
Given a generic type definition, you can construct generic types using MakeGenericType, as has been mentioned by Jeffrey Zhang.
No, you can't, There is not a base type of a Gerneric Type. If you want to get a specific generic type by type parameters, You can use MakeGenericType. For example:
//get Func<int, string> type
typeof(Func<>).MakeGenericType(typeof(int), typeof(string));
If you want to get a Generic Type from specified generic type, You can use GetGenericTypeDefinition. For example:
//get Func<,> type
typeof(Func<int, string>).GetGenericTypeDefinition();
It is Because Func< A, B > does not inherit from Func<> It is a generic based on Func<,>.
However, you will notice that
typeof(Func<int, int>).FullName // equals "System.Func`2...
typeof(Func<int, int, int>).FullName // equals "System.Func`3...
It is a bit ugly but you could use something like
YourType.FullName.StartsWith("System.Func")
Hope it helps
Edit:
Why not use YourType.GetGenericTypeDefinition()?
Because typeof(Func<int, int>).GetGenericTypeDefinition() returns Func<,>
and typeof(Func<int, int, int>).GetGenericTypeDefinition() return Func<,,>.
Func<,> and Func<,,> are not the same Type.

Generic Delegate Storage and Usage

delegate IEnumerable<T> GetFromSQLDelegate<T>(...);
public GetFromSQLDelegate myFunctionToCall;
The above does not compile because myFunctionToCall does not specify a type. I'm trying to "store" a generic delegate such that I can invoke it later as a regular generic function:
// ... somewhere in another code base ...
return MyObject.myFunctionToCall<string>(...);
C# complains because I'm not specifying a concrete type on the delegate storage property. Is there a (good) way to "store" a delegate capable of invoking a generic function without implementing various concrete type delegate scenarios?
You can store the value as System.Delegate, make it private, and define a function GetDelegate<T> that casts your stored delegate to the appropriate type:
private Delegate storedDelegate;
public myFunctionToCall<T> GetDelegate<T>() {
return (myFunctionToCall<T>)storedDelegate;
}
You can then call it like this:
return MyObject.GetDelegate<string>()(...);
There is a little bit of ugliness going on around the ()(...) syntax, but it should probably do the trick.
There are no pieces to your puzzle in C#:
you can't have non-generic variable of generic type with non-specified type
you can't create function that matches such imaginary signature
you can't call function and specify type.
So answer is NO. There are multiple different ways to achieve similar behaviors, so if you specify what your actual goal is someone will come up with an approach.

Categories

Resources