Reflection GetMethod with a type paramenter - c#

The following line is not running properly, and I'm not sure why. The Error:
System.Reflection.TargetParameterCountException: parameters do not match signature
And the line of code in question:
typeof(Resources).GetMethod("LoadAll", new Type[] { typeof(System.String), typeof(System.Type)});
Displaying all functions of the Resources class shows:
UnityEngine.Object[] FindObjectsOfTypeAll(System.Type)
T[] FindObjectsOfTypeAll[T]()
UnityEngine.Object Load(System.String)
T Load[T](System.String)
UnityEngine.Object Load(System.String, System.Type)
UnityEngine.ResourceRequest LoadAsync(System.String)
UnityEngine.ResourceRequest LoadAsync[T](System.String)
UnityEngine.ResourceRequest LoadAsync(System.String, System.Type)
UnityEngine.Object[] LoadAll(System.String, System.Type)
UnityEngine.Object[] LoadAll(System.String)
T[] LoadAll[T](System.String)
UnityEngine.Object GetBuiltinResource(System.Type, System.String)
T GetBuiltinResource[T](System.String)
Void UnloadAsset(UnityEngine.Object)
UnityEngine.AsyncOperation UnloadUnusedAssets()
Boolean Equals(System.Object)
Int32 GetHashCode()
System.Type GetType()
System.String ToString()
System.Reflection.MethodInfo[]
I'm trying to match UnityEngine.Object[] LoadAll(System.String, System.Type). Any thoughts on what may be the issue?
Bonus if you can make a line that returns a methodinfo object for "T[] LoadAllT", specific to a given type.

The issue is that you are trying to get an instance level method while the LoadAll is static.
Try this one:
typeof(Resources).GetMethod("LoadAll",
System.Reflection.BindingFlags.Static,
new Type[] { typeof(System.String),typeof(System.Type)},
null);

Related

How to check if method parameter type/return type is generic, in Roslyn?

As stated in the title, I want to check if a method params are generic + if the return type of a method is generic.
For example:
public ISet<string> Collect(MethodDeclarationSyntax method, SemanticModel semanticModel)
{
return method
.ParameterList
.Parameters
.Select(x => x.Type.ToString())
.ToImmutableHashSet();
}
Here I want to return all the types of the params for the method variable, that are not generic, but I can't find anything in the API to filter the results.
I have the same problem when checking if the return type of a method is generic.
It depends on what you have to work with. If you have an ArgumentListSyntax and thus zero or more ArgumentSyntaxes (ArgumentListSyntax.Arguments), you can get the type info from the argument expression:
var type = model.GetTypeInfo(argument.Expression).Type as INamedTypeSymbol;
And from there, the IsGenericType property. For example:
Debug.Assert(type.IsGenericType);
And if you have a MethodDeclarationSyntax object of the method, you can see if the ReturnType property is a type of GenericNameSyntax:
Debug.Assert(methodDeclaration.ReturnType is GenericNameSyntax);
cast to GenericNameSyntax to get more information about the generic type like type arguments.

Using Reflection.Emit to instantiate Generic Type with Generic Parameters

my goal is to use reflection emit to construct generic type with the generic parameters of the created generic method
so the end result of the created generic method is similar to
void DoSomeThing<T>(T arg){
var list=new List<T>();
}
so what I need is the code used to emit this fragment of code
new List<T>
and this is my try
var _assemblyName = "asm.dll";
var _assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(_assemblyName), System.Reflection.Emit.AssemblyBuilderAccess.RunAndSave);
// ApplyReflectionPermission(asm);
var _moduleBuilder = _assemblyBuilder.DefineDynamicModule("module", _assemblyName, true);
var type = _moduleBuilder.DefineType("type");
var method = type.DefineMethod("DoSomeThing", MethodAttributes.Public | MethodAttributes.Static);
var genericPrms = method.DefineGenericParameters("T");
method.SetParameters(genericPrms);
method.SetReturnType(typeof(void));
var il = method.GetILGenerator();
var listType = typeof(List<>);
var list_of_T = listType.MakeGenericType(genericPrms);
il.DeclareLocal(list_of_T);
var c = list_of_T.GetConstructor(new Type[0]);
il.Emit(OpCodes.Newobj, c);
il.Emit(OpCodes.Stloc, 0);
il.Emit(OpCodes.Ret);
type.CreateType();
_assemblyBuilder.Save(_assemblyName);
the exception is in this line of code
var c = list_of_T.GetConstructor(new Type[0]);
and it is caused by this line of code
var list_of_T = listType.MakeGenericType(genericPrms);
the exception is
System.NotSupportedException: Specified method is not supported.
at System.Reflection.Emit.TypeBuilderInstantiation.GetConstructorImpl(BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetConstructor(BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
at System.Type.GetConstructor(Type[] types)
and by digging in (MakeGenericType) method, it returns a new instanse of TypeBuilderInstantiation if any of the parameter types isn't a (RuntimeType)
the type TypeBuilderInstantiation is nothing but an empty implementation of the abstract type 'TypeInfo' [whis is an abstract impl. of the type 'Type'], which all of its method throwing not supported exception
my goal is not to create a method to return new List, it's more complicated than that, but my obstacle is the same as doing so.
thanx for helping.
Yeah, there's definitely a trick to this. Indeed you cannot call any methods on the TypeBuilderInstantiation. Instead, TypeBuilder will let you get constructors for dependent types.
The GetConstructor method provides a way to get a ConstructorInfo object that represents a constructor of a constructed generic type whose generic type definition is represented by a TypeBuilder object.
https://msdn.microsoft.com/en-us/library/ms145822(v=vs.110).aspx
You first need the generic ConstructorInfo, gotten from typeof(List<>) in the usual way...
var listDefaultConstructor = listType.GetConstructor(new Type[0]);
and then instantiate it to your particular generic implementation:
var c = TypeBuilder.GetConstructor(list_of_T, listDefaultConstructor);
Whenever you would like to call a method on an instance of Type that represents an unconstructed/dependent type, instead look for a method with the same name in the Reflection.Emit hierarchy.
Among other things, this design pattern of passing in the generic version of the MethodInfo allows you to distinguish between calls to overloaded Class<T=int>.Foo(T) and Class<T=int>.Foo(int).

C# Unable to cast error calling method with a dynamic argument

I am having an intermittent exception from my code. I have a method with a dynamic parameter. My code is essentially looping through a lot of types and registering mappings. The dynamic parameter represents an expression mapping the type to a specific property of the type.
Every few runs one call (could be any call to this method, there is no pattern) to AddIndexAttributes will fail with an 'Unable to cast' exception trying to cast the type of the dynamic expression to another expression type completely unreferenced by this code. Presumably, this is a type which has previously been mapped using this method during this run.
System.InvalidCastException: Unable to cast object of type 'System.Linq.Expressions.Expression`1[System.Func`2[Type1,System.Byte[]]]' to type 'System.Linq.Expressions.Expression`1[System.Func`2[Type2,System.Nullable`1[System.DateTimeOffset]]]'.
at CallSite.Target(Closure , CallSite , Type , PropertyInfo , Object , StructuralTypeConfiguration`1 , Dictionary`2 , Dictionary`2 )
at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid6[T0,T1,T2,T3,T4,T5](CallSite site, T0 arg0, T1 arg1, T2 arg2, T3 arg3, T4 arg4, T5 arg5)
at CallSite.Target(Closure , CallSite , Type , PropertyInfo , Object , StructuralTypeConfiguration`1 , Dictionary`2 , Dictionary`2 )
at TypeConfigurationHelper.Configure[T](StructuralTypeConfiguration`1 type) in C:\\project\TypeConfigurationHelper.cs:line 127
Where Type1 is T (see code below) and Type2 is another type in my database which is not being used or referenced anywhere in this call. Byte[] is the type of the current parameter in the loop, DateTimeOffset is, I presume, the type of a property of Type2.
The exception itself is coming from System.Core and I have been able to trace the error using VS's framework debugging. I can see it get as far as UpdateDelegates.UpdateAndExecuteVoid6 and it runs its first rule and crashes.
This code is called for all types in my EF database in one thread, one after the other in a loop.
Simplified Code:
public static void Configure<T>(StructuralTypeConfiguration<T> type) where T : class
{
var properties = typeof(T).GetProperties();
//These dictionaries keep track of whether our composite indexes are valid or not.
var compositeIndexMaximumOrder = new Dictionary<string, int>();
var compositeIndexCounts = new Dictionary<string, int>();
foreach (var property in properties)
{
//Get the property for the item on the type
PropertyInfo pi = typeof(T).GetProperty(property.Name);
//Get an expression for the type => property
//To support inherited objects we use ReflectedType instead of DeclaringType
dynamic expression = pi.ReflectedType.TypeMapExpression(pi.Name);
//Place to configure anything that is not tied to a field definition.
AddIndexAttributes<T>(pi, expression, type, compositeIndexMaximumOrder, compositeIndexCounts);
}
}
private static void AddIndexAttributes<T>(PropertyInfo property, dynamic expression, StructuralTypeConfiguration<T> type, Dictionary<string, int> compositeIndexMaximumOrder,
Dictionary<string, int> compositeIndexCounts) where T : class
{
List<IndexAttribute> indexAttributes = convertSymIndexAttributesToDotNetIndexAttributes(property, compositeIndexMaximumOrder, compositeIndexCounts);
if (indexAttributes.Count() > 0)
{
type.Property(expression).HasColumnAnnotation("Index", new IndexAnnotation(indexAttributes));
}
}
Why is this crashing? Why would it be trying to cast a dynamic value to a completely unreferenced type? I've tried to read up about what CallSite etc is actually doing, but I can't see why it would be trying to make a cast at that point.
My project is using .Net 4.5.
TypeMapExpression:
public static dynamic TypeMapExpression(this Type type, string parameterName)
{
//Get a parameter expression for the type
var parameter = System.Linq.Expressions.Expression.Parameter(type);
//Get a lambda expression for the type
return System.Linq.Expressions.Expression.Lambda(System.Linq.Expressions.Expression.Property(parameter, parameterName), parameter);
}

Get real type of generic method from StackFrame

In my logging module I have the line:
MethodBase methodBase = new StackFrame(2, false).GetMethod();
The method I inspect is a generic method and defined as T[] MyMethod<T>(). Is there a way to get its real type instead of T from methodBase?
As far as I know, you can't do this. The information in the StackFrame is retrieved not from run-time information, but from the .pdb information, correlating the return address found in the stack frame with the assembly offsets described in the .pdb. I.e. only the compile-time information is available, which of course is the open generic method.
Note that even if you manually construct a closed generic method and invoke it directly, you still get the open generic method from the .pdb. For example:
class Program
{
static void Main(string[] args)
{
MethodInfo miOpen = typeof(Program).GetMethod("Method", BindingFlags.Static | BindingFlags.NonPublic),
miClosed = miOpen.MakeGenericMethod(typeof(int));
Type type;
object[] invokeArgs = { 17, null };
int[] rgi = (int[])miClosed.Invoke(null, invokeArgs);
type = (Type)invokeArgs[1];
}
static T[] Method<T>(T t, out Type type)
{
type = GetMethodType();
return new[] { t };
}
private static Type GetMethodType()
{
StackFrame frame = new StackFrame(1, false);
MethodBase mi = frame.GetMethod();
return mi.GetGenericArguments()[0];
}
}
In the above example, the type variable value assigned at the end still references the {T} type for the open generic method, not Int32 as you would hope in your case. This, in spite of the fact that the Int32 type is retrievable from the miClosed variable reference.
If you want the specific type information, you will have to provide a mechanism in your code to determine it explicitly (e.g. pass the value of typeof(T) to the logging component from the generic method itself). The StackFrame class doesn't have the necessary information to do that for you.
Use GetGenericArguments off of the MethodBase to get what was passed into T.

use Type.GetType(string) in C# 2.0 .net but type or namespace name 't' could not be found

I'm not sure how to correct this. I have
public void get_json(String TYPE)
{
Type t = Type.GetType("campusMap." + TYPE);
t[] all_tag = ActiveRecordBase<t>.FindAll();
}
But I always just get
Error 9 The type or namespace name 't' could not be found (are you
missing a using directive or an assembly
reference?) C:_SVN_\campusMap\campusMap\Controllers\publicController.cs 109 17 campusMap
any ideas on why if I'm defining the type I am wishing to gain access to is saying it's not working? I have tried using reflection to do this with no luck. Anyone able to provide a solution example?
[EDIT] possible solution
This is trying to use the reflection and so I'd pass the string and invoke the mothod with the generic.
public void get_json(String TYPE)
{
CancelView();
CancelLayout();
Type t = Type.GetType(TYPE);
MethodInfo method = t.GetMethod("get_json_data");
MethodInfo generic = method.MakeGenericMethod(t);
generic.Invoke(this, null);
}
public void get_json_data<t>()
{
t[] all_tag = ActiveRecordBase<t>.FindAll();
List<JsonAutoComplete> tag_list = new List<JsonAutoComplete>();
foreach (t tag in all_tag)
{
JsonAutoComplete obj = new JsonAutoComplete();
obj.id = tag.id;
obj.label = tag.name;
obj.value = tag.name;
tag_list.Add(obj);
}
RenderText(JsonConvert.SerializeObject(tag_list));
}
and the error I get is in..
obj.id = tag.id;
of
't' does not contain a definition for 'id'
and same for the two name ones.
You can't pass a variable in as a generic parameter:
t[] all_tag = ActiveRecordBase<t>.FindAll();
It's complaining about the <t> part. You can't do that.
I suggest you check this out: How do I use reflection to call a generic method?
Outside of that, I'd probably do everything you want to do with the generic type in a generic method, and then use reflection to call that generic function with the runtime type variable.
public void get_json<t>()
{
t[] all_tag = ActiveRecordBase<t>.FindAll();
//Other stuff that needs to use the t type.
}
And then use the reflection tricks in the linked SO answer to call the get_json function with the generic parameter.
MethodInfo method = typeof(Sample).GetMethod("get_json");
MethodInfo generic = method.MakeGenericMethod(typeVariable);
generic.Invoke(this, null);
Your program indicates a fundamental misunderstanding about how C# works. The type of all_tag and the type value of the type argument must both be known to the compiler before the program is compiled; you do not determine that type until the program is already running, which clearly is after it is compiled.
You can't mix static compile-time typing with dynamic runtime typing like this. Once you are doing something with Reflection, the whole thing has to use Reflection.
Can you delegate the choice of type to the calling code? You can't specify a runtime type as a generic, compile-time type, but if you could delegate the choice of type to the caller, you might be able to accomplish what you want.
public ??? get_json<T>() // seems like this should return something, not void
{
var collection = ActiveRecord<T>.FindAll();
// do something with the collection
}
Called as
get_json<CampusMap.Foo>();
Even if you didn't know the type at compile time, it might would be easier to call this way via reflection, see https://stackoverflow.com/a/232621.

Categories