How to check method exists in C# with certain particular signature? - c#

I want to check if the method for certain parameters is implemented. In this scenario, I have for example these method overloads:
public class Transformations
{
public string TransformFrom(string s) { return s;}
public string TransformFrom(int i) { return "00" + i.ToString();}
public string TransformFrom(DateTime dt) { return
DateTime.ToString("MM/dd/yyyy HH:mm:ss.fff");}
}
Suppose I have decimal like:
object obj = 1M;
If I now call TransformFrom(obj), I get an exception.
Other part of my program returns unfortunately only objects, which really are concrete types like int or datetime. And I want to transform some of these objects to string so that those can be written to the log. So this is a runtime problem. Also I want that my Transformations-class is general enough to be used in other programs too, so there can be objects of any type.
Is there fast way to find out that this method overload does not exist?

Either way you are currently going to get a compile time error, even if there was an overload that accepted a decimal. You can approach this one of 2 ways depending on your needs:
To resolve this at compile time you have to cast to the correct type.
object obj = 1;
var objAsInt = (int) obj;
var result = transformationInstance.TransformFrom(objAsInt);
If there is no proper overload you will get a compile time error and you can resolve this at design time.
To resolve this at runtime use reflection to figure out if there is an overload of the type and if there is pass the instance.
object obj = 1;
var underlyingType = obj.GetType();
var method = typeof(Transformations).GetMethod("TransformFrom", new Type[] { underlyingType });
if(method != null)
{
var result = method.Invoke(transformationInstance, new []{obj});
}

It is possible to find out whether a given overload exists using reflection:
public static bool HasOverloadForArgument(Type targetType, string methodName, object arg)
{
var methodInfo = targetType.GetMethod(name: methodName, types: new[] { arg.GetType() });
return methodInfo != null;
}
Live sample
I'm not sure what is the whole idea here as there won't be much you can do when the transformation is not available during runtime.
Maybe, you'd just be best off using dynamic to avoid all the reflection stuff and caching required otherwise, e.g.
var boxedInt = (object)1;
var boxedFloat = (object)1f;
dynamic dynamicInt = boxedInt;
dynamic dynamicFloat = boxedFloat;
var intResult = new Transformations().TransformFrom(dynamicInt); // works
var floatResult = new Transformations().TransformFrom(dynamicFloat); // throws binder exception

Related

var is not detecting result of method with dynamic input

I have the following problem
private int GetInt(dynamic a)
{
return 1;
}
private void UsingVar()
{
dynamic a = 5;
var x = GetInt(a);
}
But x is still dynamic.
I don't understand why.
Since your argument a in the GetInt method call have the type dynamic, so the overload resolution occurs at run time instead of at compile time.
Based on this:
Overload resolution occurs at run time instead of at compile time if one or more of the arguments in a method call have the type dynamic, or if the receiver of the method call is of type dynamic.
Actually by using the dynamic you are using the late binding (defers to later), and it means, the compiler can't verify it because it won't use any static type analysis anymore.
The solution would be using a cast like this:
var x = (int)GetInt(a);
The following is how the compiler is treating your code:
private void UsingVar()
{
object arg = 5;
if (<>o__2.<>p__0 == null)
{
Type typeFromHandle = typeof(C);
CSharpArgumentInfo[] array = new CSharpArgumentInfo[2];
array[0] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.UseCompileTimeType, null);
array[1] = CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null);
<>o__2.<>p__0 = CallSite<Func<CallSite, C, object, object>>
.Create(Microsoft.CSharp.RuntimeBinder.Binder
.InvokeMember(CSharpBinderFlags.InvokeSimpleName, "GetInt", null, typeFromHandle, array));
}
object obj = <>o__2.<>p__0.Target(<>o__2.<>p__0, this, arg);
}

Using Runtime Generate Generic Type to Filter Using OfType<>

So dug around the Google and just can't seem to word this properly to find my answer to here I am.
this is what i currently have
Using these interfaces I will pass in a list of IConversionHelper
namespace InvestOne.Response.Mapper.Interfaces
{
public interface IConversionHelper
{
bool CanHelp(object value, Type destinationType);
}
public interface IConversionHelper<out T> :IConversionHelper
{
T Convert(object value);
}
}
Like So
public Mapper(IEnumerable<IConversionHelper> conversionHelpers)
{
_conversionHelpers = conversionHelpers;
}
Then when mapping will use these helpers like so
var propType = prop.PropertyType;
var value = #from[spectraCode.Code];
var conversionType = typeof (IConversionHelper<>).MakeGenericType(propType);
var conversionHelpers = _conversionHelpers.OfType<conversionType>();
the issue is in the last line and i understand the problem being that generics need to be at compile time and right now its not. so trying to find something similar to creating the generic type at run time only in this case filter out at run time.
the ideal solution would give me the generic runtime equivalent to
var conversionHelpers = _conversionHelpers.OfType<IConversionHelper<DateTime>>()
if the property type was a DateTimeso that later i can call helper.Convert(value)
A much easier solution would be to use Where:
var propType = prop.PropertyType;
var value = #from[spectraCode.Code];
var conversionType = typeof (IConversionHelper<>).MakeGenericType(propType);
var conversionHelpers = _conversionHelpers.Where(x => conversionType.IsAssignableFrom(x.GetType()));
Of course, the resulting sequence won't be of type IEnumerable<IConversionHelper<DateTime>>, but since you don't know the type at compile time anyway, it doesn't matter.

Call dynamic method from string

I'm trying to call a method from a dynamic without knowing its name. I have difficulties to explain this in english so there's the code:
public void CallMethod(dynamic d, string n)
{
// Here I want to call the method named n in the dynamic d
}
I want something like:d.n() but with n replaced by the string.
I want this :
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod(TheCommandString);
theMethod.Invoke(this, userParameters);
but with dynamic.
If you need the context to help you: I'm make an application that's support "mods", you put DLLs in the mod folder and it loads it and execute it. It works with dynamic (I have a dictionnary like this : Dictionnary<string, dynamic> instances;). I want the application to get the methods name from the library (with instances["topkek"].GetMethods();, I've already made this method) but then call the method with the string it returns. I don't know if what I said mean something (I'm french :/ )...
I'm using VS 2013 Express with the .Net framework 4.5, if you need more information to help me ask me.
you can write your method as follows -
public void CallMethod(dynamic d, string n)
{
d.GetType().GetMethod(n).Invoke(d, null);
}
If all methods are void, this could work. Otherwise you need to change it a bit.
public void CallMethod(string className, string methodName)
{
object dynamicObject;
// Here I want to call the method named n in the dynamic d
string objectClass = "yourNamespace.yourFolder." + className;
Type objectType = Type.GetType(objectClass);
if (objectType == null)
{
// Handle here unknown dynamic objects
}
else
{
// Call here the desired method
dynamicObject = Activator.CreateInstance(objectType);
System.Reflection.MethodInfo method = objectType.GetMethod(methodName);
if (method == null)
{
// Handle here unknown method for the known dynamic object
}
else
{
object[] parameters = new object[] { }; // No parameters
method.Invoke(dynamicObject, parameters);
}
}
}
I want to add another approach as solution:
In your case, the caller (developer of the mod) knows the method to call. Thus, this might helpful:
// In the main application:
public dynamic PerformMethodCall(dynamic obj, Func<dynamic, dynamic> method)
{
return method(obj);
{
// In a mod:
mainProgram.PerformMethodCall(myDynamicObj, n => n.myDynamicMethod());
// In another mod:
mainProgram.PerformMethodCall(myDynamicObj, n => n.anotherMethod());
This is a further development of the idea of Yuval Itzchakov in his commentary. He had suggested using a delegate.

converting a dictionary with unknown value types to json

I wrote the code below to convert a dictionary to a json string.
The catch here is that the dictionary values could be of various types
string, int, string[], int[], float[], ...
I tried using generics, but I get a compile error where I do GetParamList because it expects me to specify the actual type.
I was wondering if there is a way that I can avoid putting lots of if/else conditions to achieve what I want.
private static string GetParamList<T>(object values)
{
if (values.GetType().Equals(typeof(string[])) )
{
string[] res = (string[])values;
if (values.GetType().Equals(typeof(string[])))
{
for (int i = 0; i < res.Length; i++)
{
if (!res[i].ToString().StartsWith("\""))
{
res[i] = string.Format("\"{0}\"", res[i]);
}
}
}
return string.Join(",", res);
}
else if (values.GetType().Equals(typeof(string)))
{
return string.Format("\"{0}\"", values);
}
else// array of numbers:
{
string[] res = ((T[])values).Select(x => x.ToString()).ToArray<string>();
return string.Join(",", res);
}
}
private static string dictToJson(Dictionary<string, object> data)
{
List<string> entries = new List<string>();
foreach (var entry in data)
{
Type T = entry.Value.GetType();
entries.Add(string.Format("\"{0}\": {1}", entry.Key, GetParamList<T>(entry.Value)));
}
return "{" + string.Join(",", entries.ToArray<string>()) + "}";
}
The mistake is made here:
Type T = entry.Value.GetType();
What you're doing here is not getting a generic parameter - instead, you're getting the object of class Type which represents the parameter you want. Generics are designed to work with a type known at compile time, so that the JIT Compiler can create the definition of the class on the fly for you. You thus cannot pass in the Type object as a generic parameter.
There are, however, several ways to get around this.
The first and easiest is to have a factory method which can perform generic inference, and pass the generic parameter as dynamic. This will force the CLR to hold off until runtime to decide what type to use, and then use the best matched type for the parameters. Not that this will not work with your code as is - generic inferencing demands you use T as the type of a parameter in addition to the generic type, such as:
private static string GetParamList<T>(T[] values)
The second would be to metacode the operation and compile the call using the System.Linq.Expressions namespace, which could be significantly more verbose:
var val = Expression.Constant(entry.Value);
var method = typeof(MyType) // Where MyType is the type containing "GetParamList"
.GetMethod("GetParamList")
.MakeGenericMethod(t); // Where t is the desired type
string result = Expression
// Lambda turns an expression tree into an expressiong tree with an explicit delegate signature
.Lambda<Func<String>>(
Expression.Call(null, method, val)) // "Call the method against nothing (it's static) and pass in val (which is a constant in this case)"
.Compile() // This compiles our expression tree
.Invoke(); // Run the method
You are doing it the hard way, try this.
public List<Event_Log> GetAll()
{
List<Event_Log> result = new List<Event_Log>();
//add result collection here...
return result;
}
Thanks for recommending "Newtonsoft.Json".
I used that package this way and all the problems are solved:
private static string dictToJson(Dictionary<string, object> data)
{
string json = JsonConvert.SerializeObject(data, Formatting.None, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None,
TypeNameAssemblyFormat = FormatterAssemblyStyle.Simple
});
return json;
}

convert class string to class

I have the code below in my ASP.NET app, I would like to convert converterName variable to
Class and pass it to FillRequest<T> method.
Is it possible?
var converterName = HttpContext.Current.Items["ConverterName"] as string;
FillRequest<Web2ImageEntity>(Request.Params);
Alternatively I could do
var converterName = HttpContext.Current.Items["ConverterName"] as string;
if (converterName == "Web2ImageEntity")
FillRequest<Web2ImageEntity>(Request.Params);
but I have about 20 entity classes and I would like to find a way to write code as short as possible.
That would not be possible as the generic type needs to be specified at the compile time.
What you can do is change the FillRequest method to be something like below and then use reflection to do the desired task
FillRequest(string[] params,Type converter)
{
//Create object from converter type and call the req method
}
Or make the FillRequest take a Interface
FillRequest(string[] params, IConverter c)
{
//call c methods to convert
}
Calling this would be something like:
var type = Type.GetType(converterName);
FillRequest(Request.Params,(IConverter)Activator.CreateInstance(type));
Yes, take a look at Activator.CreateInstance():
var converterName = HttpContext.Current.Items["ConverterName"] as string;
var type = Type.GetType(converterName);
var yourObject = Activator.CreateInstance(type);
Be aware that the type must have a public parameterless constructor. Here is a link to the MSDN documentation; there are a bunch of overloads which might be useful to you:
http://msdn.microsoft.com/en-us/library/system.activator.createinstance.aspx
UPDATE: If you must pass the object to a method with a generic type, then you will run into problems because the type is not known at compile time. In that case, I would consider having all of your converters implement a common interface, something like this:
var converterName = HttpContext.Current.Items["ConverterName"] as string;
var type = Type.GetType(converterName);
var yourObject = Activator.CreateInstance(type) as IMyConverter;
if (yourObject != null)
FillRequest<IMyConverter>(yourObject);
I found code idea here. Peter Moris pointed that he took code from Jon Skeets book, so if it will be useful - high five to Jon :)
create method:
public void DoFillRequest(Type type, string[] params)
{
MethodInfo methodInfo = this.GetType().GetMethod("FillRequest");
MethodInfo genericMethodInfo = methodInfo.MakeGenericMethod(new Type[]{ type });
genericMethodInfo.Invoke(this, new object[]{ params });
}
and now call it:
var type = Type.GetType(converterName);
DoFillRequest(type, Request.Params);

Categories

Resources