Matching constructor to counterpart in generic type definition - c#

I have been thinking about this problem for a while and it feels like there must be a simple solution that I'm missing.
Let's say I have the following class:
public class Foo<T>
{
public Foo(T value)
{
}
public Foo(int value)
{
}
}
If I get all constructors on the type Foo<System.Int32> I will get back two constructors, both with a single parameter of type System.Int32 which cannot be differentiated.
If I get all constructors from the generic type definition of Foo<System.Int32> (Foo<T>) I will get back two constructors. One which accepts a generic parameter T and one that accepts a parameter of type System.Int32
// Will return two constructors with signatures that look identical.
var type = typeof(Foo<int>);
var ctors1 = type.GetConstructors();
// Will return two constructors as well. Parameters can be differentiated.
var genericTypeDefinition = typeof(Foo<int>).GetGenericTypeDefinition();
var ctors2 = genericTypeDefinition.GetConstructors();
Is there a way to match a constructor to its counterpart in its generic type definition?

For Comparing the ctors in both cases you can compare their MetadataToken.
Example:
foreach (var item in ctors1)
{
var ctorMatch = ctors2.SingleOrDefault(c => c.MetadataToken == item.MetadataToken);
}

Related

Method return type like Generic Class Type

Is possible set method return type, like type to generic class ?
I have Generic Class:
class Generic<T>
{
public static DataSet test(T input)
{
//Some logic...
}
}
Another Class, where i call my generic class.
It works for this examples:
Generic<int>.test(10);
But if i want to call different methods, with complex unknown date types, i don't know how i put their date type like Generic Type.
For Example
var data = Data.GetData(); // return List<string,int>
var data2 = Data.GetData2() // return Tuple<List<string>, List<int>>
I try use method GetType, for get returns method type, something like this, but it doesn't work.
Generic<data.GetType()>.test(data);
Is it possible, something like this ?
No, you can't specify the generic type at runtime without reflection, but there may be other ways to solve your problem. You could put the generic constraint on the method instead of the class:
class Generic
{
public static dynamic Test<T>(T input)
{
//Some logic...
}
}
which then can be inferred from the input type:
Generic.Test(data);
Return Type of a function is known in compile time.
Therefore if I understood your question correctly what you're asking for isn't possible. TL;DR You can't set return type in runtime.

Generic type inheritance

public class BaseGenericType<T>
{
}
public class SubGenericType<T>: BaseGenericType<List<T>>
{
}
I have two generic types above, which one inherits from another but is still generic.
The strange thing I can't figure out is that typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<>)) returns false. And typeof(SubGenericType<>).IsSubclassOf(typeof(BaseGenericType<List<>>)) still returns false. I've tried GetGenericTypeDefinition() and MakeGenericType() and GetGenericArguments() to check the inheritance, still not working. But typeof(SubGenericType<int>).IsSubclassOf(typeof(BaseGenericType<List<int>>)) returns true.
What I want is to get all classes by reflection then grab the specific class which inherits from a generic type passed in.
e.g.
(1)List<int> -->
(2)get generic type definition ==> List<T> -->
(3)make generic ==> BaseGenericType<List<T>> -->
(4)find subclass ==> SubGenericType<T>
(5)make generic ==> SubGenericType<int>
In step (4) I find nothing although I actually have that SubGenericType<T>. Why is that?
Once I wrote this method to check generic type inheritance:
static bool IsSubclassOfOpenGeneric(Type generic, Type toCheck)
{
while (toCheck != null && toCheck != typeof(object))
{
var cur = toCheck.IsGenericType ? toCheck.GetGenericTypeDefinition() : toCheck;
if (generic == cur)
{
return true;
}
toCheck = toCheck.BaseType;
}
return false;
}
This returns true:
IsSubclassOfOpenGeneric(typeof(BaseGenericType<>), typeof(SubGenericType<int>))
It doesn't check interfaces though.
By the way, usually if you have relations like this, and you write all the classes yourself, consider using interfaces. It is much easier to handle. You can for instance have a IGenericType interface without generic argument. Sometome you just do not care about the generic type and just want to access members which do not depend on the generic type. Sometimes you want to simply check if it is one of those. And you can use type variance.
Finally, I figured it out.
This is the very solution. To explain in details, I have to introduce some non-abstract coding:
It's about a value converter. My purpose is simple, to let users add their own value converters. In the conversion step, I will check built-in types' converters first(as IConvertible), if not found, I'll first search the current executing assembly for all custom converter classes that inherit a specific abstract class provided by me. And an interface is implemented by that abstract class to make constraint for later reflection. Then I filter those reflected classes for the one that matches.
Here is the base class and interface(all nested):
private interface ICustomConverter
{
Type SourceType { get; }
object CallConvert(string input);
}
public abstract class CustomConverter<T> : ICustomConverter
{
public abstract T Convert(string input);
public Type SourceType
{
get { return typeof (T); }
}
object ICustomConverter.CallConvert(string input)
{
return Convert(input);
}
}
I've made the interface private in the parent class and implemented explicitly. So that the method CallConvert() won't be called outside.
The generic parameter T is the Type to convert the string value to.
e.g.
public class Int32Converter:CustomConverter<int>
{
}
This is easy to handle since the conversion target type isn't generic. all I need to do is to get all types that implement ICustomConverter, and make a generic type from CustomConverter<T> with the given int, thus CustomConverter<int>. Then I filter those classes for the one that derives from CustomConverter<int>, and here I found Int32Converter.
Later I came across this situation:
public class ListConverter<T>:CustomConverter<List<T>>
{
}
and
public class DictConverter<T,U>:CustomConverter<Dictionary<T,U>>
{
}
I used the same process to deal with them. But after I made a generic type CustomConverter<List<T>>, I found that ListConverter<T> does not derive from CustomConverter<List<T>> and CustomConverter<List<T>> is not assignable from
ListConverter<T>(which I checked with IsAssignableFrom() and IsSubclassOf()).
I guess the reason is that generic type stands for more than one type before the generic parameters are assigned.
This sounds weird but it is true. The compiler doesn't know that the T in CustomConverter<List<T>> and ListConverter<T> stand for the same TYPE
In fact, I can write it like CustomConverter<List<T>> and ListConverter<U>, and then you tell me the inheritance relationship between them.
And base type checking won't work here since ListConverter<T> and DictConverter<T,U> share the same root class. This means if I look for ListConverter<T>, I'll get DictConverter<T,U> too with the base class checking method(hierarchy loop checking). So I still have to make generic type, then check generic arguments and do type comparing.
The point is that I need to look for the specific class whose generic parameters are used as the generic arguments in its parent class's generic parameter. Sort of twisted but now it is clear.
Here is the final Convertion solution:
public static object ToObject(Type type, string value)
{
if (type == null)
throw new ArgumentNullException("type");
if (!typeof (IConvertible).IsAssignableFrom(type))
{
if (type.IsGenericType)
{
Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
Type genericConverter =
typeof (ICustomConverter).Assembly.Types(Flags.Public)
.SingleOrDefault(
t =>
typeof (ICustomConverter).IsAssignableFrom(t) && t.IsGenericType &&
t.GetGenericArguments().Length == type.GetGenericArguments().Length && !t.IsAbstract &&
t.MakeGenericType(type.GetGenericArguments()).IsSubclassOf(converterType));
if (genericConverter != null)
{
Type customConverter = genericConverter.MakeGenericType(type.GetGenericArguments());
object instance = customConverter.CreateInstance();
if (instance is ICustomConverter)
return ((ICustomConverter) instance).CallConvert(value);
}
}
else
{
Type converterType = typeof (CustomConverter<>).MakeGenericType(type);
Type customConverter =
typeof (ICustomConverter).Assembly.Types(Flags.Public)
.SingleOrDefault(t => t.IsSubclassOf(converterType));
if (customConverter != null)
{
object instance = customConverter.CreateInstance();
if (instance is ICustomConverter)
return ((ICustomConverter) instance).CallConvert(value);
}
}
throw new ArgumentException("type is not IConvertible and no custom converters found", type.Name());
}
TypeConverter converter = TypeDescriptor.GetConverter(type);
return converter.ConvertFromString(value);
}
I also checked GetGenericArguments().Length in case List<T> messes with Dictionary<TKey,TValue>.
Note: some custom extension methods are used.

C# Func<T,TResult> arguments validation

Imagine the Func Func<Arguments, bool?>, where Arguments is an abstract class. Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. Of course the type of Arguments is important for validation before the Func is called. Is there a way to get the type of Arguments?
e.g.:
public bool? test(Arguments arg) {
Func test = Func<SomeArguments, bool?>;
Type argType = GetFirstArgumentType(test); // gives SomeArguments.GetType();
if (arg.GetType() == argType) {
return test(new SomeArguments());
}
return null;
}
You can use Type.GetGenericArguments to get the System.Type of the first generic argument to your Func<T,bool?>.
That being said, it would likely be easier to store a Dictionary<Type, Delegate> to hold your types, and just do a direct lookup instead.
Based on your description, " Somewhere, for some reason I create a list of these functions with all kind of derived classes as arguments. " I might suggest that you use a parameter constraint:
public bool? test<T>(T arg) where T :Arguments, new()
{
var type = typeof(T);
// ...
}
This will get you the type checking you describe.

Typecast to a type from just the string representation of the type name

sTypeName = ... //do some string stuff here to get the name of the type
/*
The Assembly.CreateInstance function returns a type
of System.object. I want to type cast it to
the type whose name is sTypeName.
assembly.CreateInstance(sTypeName)
So, in effect I want to do something like:
*/
assembly.CreateInstance(sTypeName) as Type.GetType(sTypeName);
How do I do that? And, what do I take on the left side of the assignment expression, assuming this is C# 2.0. I don't have the var keyword.
Usually you let all classes, you want to instantiate this dynamically, implement a common interface, lets say IMyInterface. You can create an instance from the classname string like this:
Assembly asm = Assembly.GetExecutingAssembly();
string classname = "MyNamespace.MyClass";
Type classtype = asm.GetType(classname);
// Constructor without parameters
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype);
// With parameters (eg. first: string, second: int):
IMyInterface instance = (IMyInterface)Activator.CreateInstance(classtype,
new object[]{
(object)"param1",
(object)5
});
Even if you dont have a common interface, but know the name of the method (as string) you can invoke your methods like this (very similar for properties, event and so on):
object instance = Activator.CreateInstance(classtype);
int result = (int)classtype.GetMethod("TwoTimes").Invoke(instance,
new object[] { 15 });
// result = 30
The example class:
namespace MyNamespace
{
public class MyClass
{
public MyClass(string s, int i) { }
public int TwoTimes(int i)
{
return i * 2;
}
}
}
Unfortunately there's no way in .NET to do what you want.
Possible partial solutions are:
If you know the type at compile-time (unlikely, since you're creating it at run-time from a string) then simply cast to that type:
YourType t = (YourType)Activator.CreateInstance(sTypeName);
If you know that all the possible types will implement a specific, common interface then you can cast to that interface instead:
IYourInterface i = (IYourInterface)Activator.CreateInstance(sTypeName);
If you can't do either of the above then, unfortunately, you're stuck with object and reflection.
.
Define a generic method in your class, and then you can cast like this:
public T Cast<T>(object obj)
{
return (T) obj;
}
string sTypename = "SomeClassName";
MethodInfo cast = this.GetType().GetMethod("Cast");
MethodInfo genericCast = cast.MakeGenericMethod(new Type[] { Type.GetType(sTypename) });
Object castedValue = genericCast.Invoke(this, new object[] { instanceToBeCasted });
But then I think, what is the point of such casting if you cannot store the casted value in a variable of the actual type, precisely because you don't know the actual type at the time of writing the code?

extension methods with generics - when does caller need to include type parameters?

Is there a rule for knowing when one has to pass the generic type parameters in the client code when calling an extension method?
So for example in the Program class why can I (a) not pass type parameters for top.AddNode(node), but where as later for the (b) top.AddRelationship line I have to pass them?
class Program
{
static void Main(string[] args)
{
// Create Graph
var top = new TopologyImp<string>();
// Add Node
var node = new StringNode();
node.Name = "asdf";
var node2 = new StringNode();
node2.Name = "test child";
top.AddNode(node);
top.AddNode(node2);
top.AddRelationship<string, RelationshipsImp>(node,node2); // *** HERE ***
}
}
public static class TopologyExtns
{
public static void AddNode<T>(this ITopology<T> topIf, INode<T> node)
{
topIf.Nodes.Add(node.Key, node);
}
public static INode<T> FindNode<T>(this ITopology<T> topIf, T searchKey)
{
return topIf.Nodes[searchKey];
}
public static void AddRelationship<T,R>(this ITopology<T> topIf, INode<T> parentNode, INode<T> childNode)
where R : IRelationship<T>, new()
{
var rel = new R();
rel.Child = childNode;
rel.Parent = parentNode;
}
}
public class TopologyImp<T> : ITopology<T>
{
public Dictionary<T, INode<T>> Nodes { get; set; }
public TopologyImp()
{
Nodes = new Dictionary<T, INode<T>>();
}
}
With respect to the second example, the compiler does not know what type you want for R; it only knows that it must implement IRelationship<T> and have a public default constructor. It can't infer it from any of the parameters you pass to the method because they are of type T. In that case, you need to tell it what class you want to be used for R. If you were to pass in, instead of create an instance of R, as an argument, it would be able to infer the type and you wouldn't need to supply them.
In the first case, you don't need to supply the types because the arguments are of the type and thus the compiler can infer the types that you mean.
Generally, you don't have to explicitly specify the type. You need it when the type is in fact an argument - and example to this is the linq function .Cast - it's type tells it what to do: Cast<Employee>()
In your case this is quite simple: AddRelationship<T,R> has three argumenta, all of type T - how can R be inferred?
I haven't done this particular setup, but my understanding of type inference is that the caller would not need to specify the type. this ITopology<T> topIf will refer to an instance in which the type is already declared. The extension method should pick up the same type parameter implicitly.
A lot of the LINQ extension methods are based on generic extension methods of IEnumerable. It's the same pattern that you're using. That's a good place to start looking.
And as always, test.
I think it is because you do not include any argument with type R in the function.

Categories

Resources