C# Reflection - Casting Parameter to Type - c#

I have a ConvertMethods class that can be dynamically Invoked.
public class ConvertMethods
{
public ConvertMethods()
{
Type type = typeof(ConvertMethods);
methodInfos = type.GetMethods(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
}
public Type GetParameterType(string methodName)
{
foreach (var method in methodInfos) {
if (method.Name == methodName) {
return method.GetParameters()[0].GetType();
}
}
throw new MissingMethodException("ConvertMethods", methodName);
}
public Type GetReturnType(string methodName)
{
foreach (var method in methodInfos) {
if (method.Name == methodName) {
return method.ReturnType;
}
}
throw new MissingMethodException("ConvertMethods", methodName);
}
public object InvokeMethod(string methodName, object parameter)
{
foreach (var method in methodInfos) {
if (method.Name == methodName) {
return InvokeInternal(method, parameter);
}
}
throw new MissingMethodException("ConvertMethods", methodName);
}
public static TimeSpan SecondsToTimeSpan(long seconds)
{
return TimeSpan.FromSeconds(seconds);
}
private object InvokeInternal(MethodInfo method, object parameter)
{
return method.Invoke(null, new[] { parameter });
}
private MethodInfo[] methodInfos;
}
Potentially, every value that needs to be converted comes from the database as a string. I want to dynamically cast/convert it it to whatever the Parameter Type is of the Invoked method. Here is what I have:
class Program
{
static void Main(string[] args)
{
string methodName = "SecondsToTimeSpan";
string value = "10";
ConvertMethods methods = new ConvertMethods();
Type returnType = methods.GetReturnType(methodName);
Type paramType = methods.GetParameterType(methodName);
object convertedParameter = (paramType)value; // error on this line
var result = methods.InvokeMethod(methodName, convertedParameter);
Console.WriteLine(result.ToString());
}
}
How can I property convert or convert the String value to whatever type paramType contains?

object convertedParameter = TypeDescriptor.GetConverter(paramType).ConvertFromString(value);
will do what you want.

Related

How to create a generic method to create an instance of class at n depth level?

I have created a generic method(NewIfNull) to create an instance of class if object is null. But currently I am supplying the property name as hard-coded which I don't want to do. Please help if there is any way to do this.
static void Main(string[] args)
{
RnD rnD = new RnD();
rnD.NewIfNull("A").A.NewIfNull("B").B.NewIfNull("C");
if(rnD.A.B.C != null)
{
}
}
class RnD
{
public A A { get; set; }
}
class A
{
public B B { get; set; }
}
class B
{
public C C { get; set; }
}
class C
{
}
public static class ExtensionClass1
{
public static T NewIfNull<T>(this T obj, string propName)
{
if (obj != null)
{
if (obj.GetType().GetProperty(propName) != null &&
obj.GetType().GetProperty(propName).GetValue(obj) == null)
{
Type type =
obj.GetType().GetProperty(propName).PropertyType;
if (type.IsClass)
{
var getobj = Activator.CreateInstance(type);
obj.GetType().GetProperty(propName).SetValue(obj,
getobj);
}
}
}
return obj;
}
}
I don't want to pass "A", "B" and "C" as hard-coded in below code.
rnD.NewIfNull("A").A.NewIfNull("B").B.NewIfNull("C");
A simple answer without trying to understand what you are actually trying to do is to use nameof:
rnD.NewIfNull(nameof(RnD.A)).A.NewIfNull(nameof(A.B)).B.NewIfNull(nameof(B.C));
You can use expressions to do this.
public static TProperty NewIfNull<TObj, TProperty>(this TObj obj, Expression<Func<TObj, TProperty>> selector)
{
if (!(selector.Body is MemberExpression memberExpression)
|| !(memberExpression.Member is PropertyInfo propertyInfo))
{
throw new ArgumentException("Expected a lambda in the form x => x.Property", nameof(selector));
}
var property = (TProperty)propertyInfo.GetValue(obj);
if (property == null)
{
// We already know that typeof(TProperty).IsClass is true - if it
// wasn't, then 'property' could not have been null above.
property = (TProperty)Activator.CreateInstance(typeof(TProperty));
propertyInfo.SetValue(obj, property);
}
return property;
}
Then you can call it like:
rnD.NewIfNull(x => x.A).NewIfNull(x => x.B).NewIfNull(x => x.C);
You can quite easily modify it to initialise all of your properties at the same time:
public static void NewIfNull<TObj, TProperty>(this TObj obj, Expression<Func<TObj, TProperty>> selector)
{
object subject = obj;
foreach (var member in GetMembers().Reverse())
{
if (!(member.Member is PropertyInfo propertyInfo))
{
throw new ArgumentException("Member was not a property", nameof(selector));
}
var property = propertyInfo.GetValue(subject);
if (property == null)
{
property = Activator.CreateInstance(propertyInfo.PropertyType);
propertyInfo.SetValue(subject, property);
}
subject = property;
}
IEnumerable<MemberExpression> GetMembers()
{
for (var member = GetMember(selector.Body); member != null; member = GetMember(member.Expression))
{
yield return member;
}
}
MemberExpression GetMember(Expression expr)
{
if (expr is ParameterExpression)
{
return null;
}
if (expr is MemberExpression member)
{
return member;
}
throw new ArgumentException("Expected a lambda in the form x => x.A.B.C", nameof(selector));
}
}
And call it like:
rnD.NewIfNull(x => x.A.B.C);

c# - How to set the correct order of the parameters invoking with reflection?

I need to call any method from any class (in the same assembly) and passing trought the parameters. So far so good (I believe), but Invoke ask me for an object array (which I can get) but in the same order that is predefined in the method.
I made this class for the parameters:
public class Parametros {
public string type { get; set; }
public string name { get; set; }
public object value { get; set; }
}
and my method to "invoke" is the following:
public static void Executar(string namespaceClass, string metodo,List<Parametros> parametros) {
Type type = Type.GetType(namespaceClass);
Object obj = Activator.CreateInstance(type);
MethodInfo methodInfo = type.GetMethod(metodo);
List<object> myParams = new List<object>();
foreach (Parametros myparam in parametros) {
//Get and order the params
myParams.Add(myparam.value);
}
methodInfo.Invoke(obj, myParams.ToArray());
}
Without the solution of specify the order in my class Parametros, there is any way to accomplishment this, getting the names of the parameters and send it to the invoke method?
Finally I get it, I will let the answer for anyone who needs it. It works with static and non-static types. Take in consideration that namespaceClass must be Namespace.etc.Class
public static void Executar(string namespaceClass, string metodo, List<Parametros> parametros = null)
{
Type type = Type.GetType(namespaceClass);
MethodInfo methodInfo = type.GetMethod(metodo);
Object objectToInvoke;
if (type.IsAbstract && type.IsSealed)
{
objectToInvoke = type;
}
else {
objectToInvoke = Activator.CreateInstance(type);
}
ParameterInfo[] parametersFromMethod = methodInfo.GetParameters();
if (parametros != null || (methodInfo != null && parametersFromMethod != null && parametersFromMethod.Length > 0))
{
List<object> myParams = new List<object>();
foreach (ParameterInfo parameterFound in parametersFromMethod)
{
Parametros parametroEspecificado = parametros.Where(p => p.name == parameterFound.Name).FirstOrDefault();
if (parametroEspecificado != null)
{
myParams.Add(parametroEspecificado.value);
}
else
{
myParams.Add(null);
}
}
methodInfo.Invoke(objectToInvoke, myParams.ToArray());
}
else
{
methodInfo.Invoke(objectToInvoke, null);
}
}

WP7: Type.GetMethods throws MethodAccessException. Is there a workaround for this bug?

I try to get a list of all methods of a type. Type provides the GetMethods method to do this. But unfortunately it seems to be incorrectly implemented. It works properly as long as there is no overridden generic method on the reflected type. In this special case a MethodAccessException is thrown.
Does anyone have a workaround for this WP7 bug? I'm fine if all methods except the generic ones are returned.
Here is a sample of a class that will throw an exception. Note: the none generic return value is intended to prove that the return value is not involved in the problem. Furthermore, the base method can be changed to abstract and the problem still remains.
public abstract class BaseClassWithGenericMethod
{
public virtual System.Collections.IList CreateList<T>()
{
return new List<T>();
}
}
public class DerivedClassWithGenericMethod
: BaseClassWithGenericMethod
{
public override System.Collections.IList CreateList<T>()
{
return new List<T>();
}
}
I'd grab them all (note the BindingFlags.DeclaredOnly in GetMethods) and then filter out those that are generic methods (MethodInfo.IsGenericMethod).
Sorry for the VB, I know the whole world wants C# these days, but...
Public Function GetListOfMethods() As List(Of MethodInfo)
Dim d As New DerivedClassWithGenericMethod
Dim myArrayMethodInfo() As Reflection.MethodInfo
myArrayMethodInfo = d.GetType.GetMethods(BindingFlags.Instance _
Or BindingFlags.Public _
Or BindingFlags.DeclaredOnly)
Dim myArrayMethodInfoList As New List(Of MethodInfo)
For Each m As MethodInfo In myArrayMethodInfo
If Not m.IsGenericMethod Then
myArrayMethodInfoList.Add(m)
End If
Next
Return myArrayMethodInfoList
End Function
I just tested on WP7 using your sample classes and it works fine.
Finally I got it working. The following Type extension methods return exactly the same result as the .NET 4.0 implementation but without the MethodAccess exceptions thrown by WP7:
public static class TypeExtensions
{
public static MethodInfo GetMethodWp7Workaround(this Type type, string name)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, null, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, Type[] types)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, types, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
return GetMethod(type, name, bindingAttr, null, CallingConventions.Any, null, null);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance, null, CallingConventions.Any, types, modifiers);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr, Binder binder, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, bindingAttr, binder, CallingConventions.Any, types, modifiers);
}
public static MethodInfo GetMethodWp7Workaround(this Type type, string name, BindingFlags bindingAttr, Binder binder, CallingConventions callConvention, Type[] types, ParameterModifier[] modifiers)
{
if (name == null)
{
throw new ArgumentNullException("name");
}
if (types == null)
{
throw new ArgumentNullException("types");
}
if (types.Any(t => t == null))
{
throw new ArgumentNullException("types");
}
return GetMethod(type, name, bindingAttr, binder, callConvention, types, modifiers);
}
private static MethodInfo GetMethod(
Type type,
string name,
BindingFlags bindingFlags,
Binder binder,
CallingConventions callConvention,
Type[] types,
ParameterModifier[] modifiers)
{
if ((bindingFlags & BindingFlags.DeclaredOnly) == BindingFlags.DeclaredOnly)
{
return types == null
? type.GetMethod(name, bindingFlags)
: type.GetMethod(name, bindingFlags, binder, callConvention, types, modifiers);
}
bool isBaseType = false;
bindingFlags = bindingFlags | BindingFlags.DeclaredOnly;
MethodInfo result = null;
while (result == null && type != null)
{
result =
types == null
? type.GetMethod(name, bindingFlags)
: type.GetMethod(name, bindingFlags, binder, callConvention, types, modifiers);
if (isBaseType && result != null && result.IsPrivate)
{
result = null;
}
type = type.BaseType;
if (!isBaseType)
{
isBaseType = true;
bindingFlags = bindingFlags & (~BindingFlags.Static);
}
}
return result;
}
public static MethodInfo[] GetMethodsWp7Workaround(this Type type)
{
return type.GetMethodsWp7Workaround(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance);
}
public static MethodInfo[] GetMethodsWp7Workaround(this Type type, BindingFlags flags)
{
if ((flags & BindingFlags.DeclaredOnly) == BindingFlags.DeclaredOnly)
{
return type.GetMethods(flags);
}
flags = flags | BindingFlags.DeclaredOnly;
Type currentType = type;
bool isBaseType = false;
var methods = new List<MethodInfo>();
while (currentType != null)
{
var newMethods = currentType.GetMethods(flags).Where(m => ShouldBeReturned(m, methods, isBaseType));
methods.AddRange(newMethods);
currentType = currentType.BaseType;
if (!isBaseType)
{
isBaseType = true;
flags = flags & (~BindingFlags.Static);
}
}
return methods.ToArray();
}
private static bool ShouldBeReturned(
MethodInfo method,
IEnumerable<MethodInfo> foundMethods,
bool isCurrentTypeBaseType)
{
return !isCurrentTypeBaseType || (!method.IsPrivate && !HasAlreadyBeenFound(method, foundMethods));
}
private static bool HasAlreadyBeenFound(
MethodInfo method,
IEnumerable<MethodInfo> processedMethods)
{
if (!method.IsGenericMethodDefinition)
{
return processedMethods.Any(m => m.GetBaseDefinition().Equals(method.GetBaseDefinition()));
}
return processedMethods.Any(
m => m.Name == method.Name &&
HaveSameGenericArguments(m, method) &&
HaveSameParameters(m, method));
}
private static bool HaveSameParameters(MethodInfo method1, MethodInfo method2)
{
var parameters1 = method1.GetParameters();
var parameters2 = method2.GetParameters();
return parameters1.Length == parameters2.Length &&
parameters1.All(parameters2.Contains);
}
private static bool HaveSameGenericArguments(MethodInfo method1, MethodInfo method2)
{
var genericArguments1 = method1.GetGenericArguments();
var genericArguments2 = method2.GetGenericArguments();
return genericArguments1.Length == genericArguments2.Length;
}
}
You will get the same result for the following class with .NET 4.0 and this workaround on WP7:
internal class TestBaseClass
{
private static void BasePrivateStaticMethod() { }
private void BasePrivateMethod() { }
private void BasePrivateGenericMethod<T>() { }
protected static void BaseProtectedStaticMethod() { }
protected void BaseProtectedMethod() { }
protected void BaseProtectedGenericMethod<T>() { }
protected virtual void OverriddenProtectedMethod() { }
protected virtual void OverriddenProtectedGenericMethod<T>() { }
internal static void BaseInternalStaticMethod() { }
internal void BaseInternalMethod() { }
internal void BaseInternalGenericMethod<T>() { }
internal virtual void OverriddenInternalMethod() { }
internal virtual void OverriddenInternalGenericMethod<T>() { }
public static void BasePublicStaticMethod() { }
public void BasePublicMethod() { }
public void BasePublicGenericMethod<T>() { }
public virtual void OverriddenPublicMethod() { }
public virtual void OverriddenPublicGenericMethod<T>() { }
}
internal class TestClass : TestBaseClass
{
public string Property
{
get { return null; }
}
private static void PrivateStaticMethod() { }
private void PrivateMethod() { }
private void PrivateGenericMethod<T>() { }
protected static void ProtectedStaticMethod() { }
protected void ProtectedMethod() { }
protected static void ProtectedGenericMethod<T>() { }
internal static void InternalGenericMethod<T>() { }
internal void InternalMethod() { }
internal static void InternalStaticMethod() { }
public static void PublicStaticMethod() { }
public void PublicMethod() { }
public static void PublicGenericMethod<T>() { }
internal override void OverriddenInternalMethod()
{
base.OverriddenInternalMethod();
}
protected override void OverriddenProtectedMethod()
{
base.OverriddenProtectedMethod();
}
public override void OverriddenPublicMethod()
{
base.OverriddenPublicMethod();
}
internal override void OverriddenInternalGenericMethod<T>()
{
base.OverriddenInternalGenericMethod<T>();
}
protected override void OverriddenProtectedGenericMethod<T>()
{
base.OverriddenProtectedGenericMethod<T>();
}
public override void OverriddenPublicGenericMethod<T>()
{
base.OverriddenPublicGenericMethod<T>();
}
}
Could you actually be misinterpreting the behavior you are seeing? I am thinking you are experiencing a valid security access issue and nothing to do with the implementation of reflection on WP7 (other than its security model).
Look at this post. Could the type you are reflecting, any of the methods in question or the Type assigned to T in your particular case be marked as security critical with the SecurityCriticalAttribute?
I gotta admit that I doubted what you are reporting but it is indeed easily reproducible and does look like a bug to me. I think you should report it on Microsoft connect.
As for work arounds...
This will get you the members of the derived class and then the base class (including the generic) without error:
var m = new DerivedClassWithGenericMethod();
foreach (var method in m.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
Debug.WriteLine(method.Name);
foreach (var method in m.GetType().BaseType.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly))
Debug.WriteLine(method.Name);
This can be generalized (quick and dirty implementation) somewhat like so (The EqualityComprarer should filter out base class members that are overriden or hidden by derived classes):
class MethodComparer : IEqualityComparer<MethodInfo>
{
public bool Equals(MethodInfo x, MethodInfo y)
{
return GetHashCode(x) == GetHashCode(y);
}
public int GetHashCode(MethodInfo obj)
{
int hash = obj.Name.GetHashCode();
foreach (var param in obj.GetParameters())
hash ^= param.ParameterType.GetHashCode();
if (obj.IsGenericMethodDefinition)
{
hash ^= obj.GetGenericArguments().Length.GetHashCode();
}
else if (obj.IsGenericMethod)
{
foreach (var t in obj.GetGenericArguments())
hash ^= t.GetHashCode();
}
return hash;
}
}
static class Ext
{
public static MethodInfo[] MyGetMethods(this Type t)
{
if (t == null)
return new MethodInfo[] { };
var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
var baseMethods = from m in t.BaseType.MyGetMethods()
where !methods.Contains(m, new MethodComparer())
select m;
return methods.Concat(baseMethods).ToArray();
}
}
var m = new DerivedClassWithGenericMethod();
foreach (var method in m.GetType().MyGetMethods())
Debug.WriteLine(method.Name);
Theres a GetMethods(BindingFlags). Try filtering out the methods you are getting with the BindingFlags argument.

Invoking a method of a Generic Class

Here is the Context :
I try to code a mapper for converting my DomainModel Objects to ViewModel Ojects dynamically. The problem I get, it's when I try to invoke a method of generic class by reflection I get this error :
System.InvalidOperationException : Late bound operations cannot be performed on types or methods for which ContainsGenericParameters is true.
Can someone help-me to figure out where is the fault ? It would be greatly appreciated
Here is the Code (I tried to simplified it) :
public class MapClass<SourceType, DestinationType>
{
public string Test()
{
return test
}
public void MapClassReflection(SourceType source, ref DestinationType destination)
{
Type sourceType = source.GetType();
Type destinationType = destination.GetType();
foreach (PropertyInfo sourceProperty in sourceType.GetProperties())
{
string destinationPropertyName = LookupForPropertyInDestinationType(sourceProperty.Name, destinationType);
if (destinationPropertyName != null)
{
PropertyInfo destinationProperty = destinationType.GetProperty(destinationPropertyName);
if (destinationProperty.PropertyType == sourceProperty.PropertyType)
{
destinationProperty.SetValue(destination, sourceProperty.GetValue(source, null), null);
}
else
{
Type d1 = typeof(MapClass<,>);
Type[] typeArgs = { destinationProperty.GetType(), sourceType.GetType() };
Type constructed = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(constructed, null);
MethodInfo theMethod = d1.GetMethod("Test");
string toto = (string)theMethod.Invoke(o,null);
}
}
}
}
private string LookupForPropertyInDestinationType(string sourcePropertyName, Type destinationType)
{
foreach (PropertyInfo property in destinationType.GetProperties())
{
if (property.Name == sourcePropertyName)
{
return sourcePropertyName;
}
}
return null;
}
}
You need to call GetMethod on the constructed type constructed, not on the type definition d1.
// ...
Type d1 = typeof(MapClass<,>);
Type[] typeArgs = { destinationProperty.GetType(), sourceType.GetType() };
Type constructed = d1.MakeGenericType(typeArgs);
object o = Activator.CreateInstance(constructed, null);
MethodInfo theMethod = constructed.GetMethod("Test");
string toto = (string)theMethod.Invoke(o, null);
// ...

Getting a delegate from methodinfo

I have a drop down list that is populated by inspecting a class's methods and including those that match a specific signature. The problem is in taking the selected item from the list and getting the delegate to call that method in the class. The first method works, but I cannot figure out part of the second.
For example,
public delegate void MyDelegate(MyState state);
public static MyDelegate GetMyDelegateFromString(string methodName)
{
switch (methodName)
{
case "CallMethodOne":
return MyFunctionsClass.CallMethodOne;
case "CallMethodTwo":
return MyFunctionsClass.CallMethodTwo;
default:
return MyFunctionsClass.CallMethodOne;
}
}
public static MyDelegate GetMyDelegateFromStringReflection(string methodName)
{
MyDelegate function = MyFunctionsClass.CallMethodOne;
Type inf = typeof(MyFunctionsClass);
foreach (var method in inf.GetMethods())
{
if (method.Name == methodName)
{
//function = method;
//how do I get the function to call?
}
}
return function;
}
How do I get the commented out section of the second method to work? How do I cast the MethodInfo into the delegate?
Thanks!
Edit: Here is the working solution.
public static MyDelegate GetMyDelegateFromStringReflection(string methodName)
{
MyDelegate function = MyFunctionsClass.CallMethodOne;
Type inf = typeof(MyFunctionsClass);
foreach (var method in inf.GetMethods())
{
if (method.Name == methodName)
{
function = (MyDelegate)Delegate.CreateDelegate(typeof(MyDelegate), method);
}
}
return function;
}
public static Delegate CreateDelegate(this MethodInfo methodInfo, object target) {
Func<Type[], Type> getType;
var isAction = methodInfo.ReturnType.Equals((typeof(void)));
var types = methodInfo.GetParameters().Select(p => p.ParameterType);
if (isAction) {
getType = Expression.GetActionType;
}
else {
getType = Expression.GetFuncType;
types = types.Concat(new[] { methodInfo.ReturnType });
}
if (methodInfo.IsStatic) {
return Delegate.CreateDelegate(getType(types.ToArray()), methodInfo);
}
return Delegate.CreateDelegate(getType(types.ToArray()), target, methodInfo.Name);
}
You'll need to call some form of Delegate.CreateDelegate(), depending on whether the method in question is a static or instance method.
Here is a simpler version of Sagi's solution using Expression.GetDelegateType() instead of manually detecting whether an Action or Func is needed:
public static Delegate CreateDelegate(this MethodInfo methodInfo, object target)
{
var parmTypes = methodInfo.GetParameters().Select(parm => parm.ParameterType);
var parmAndReturnTypes = parmTypes.Append(methodInfo.ReturnType).ToArray();
var delegateType = Expression.GetDelegateType(parmAndReturnTypes);
if (methodInfo.IsStatic)
return methodInfo.CreateDelegate(delegateType);
return methodInfo.CreateDelegate(delegateType, target);
}

Categories