Dynamically calling method and class name - c#

I have some cases where I have to call method names from class names.
string scenario1 = "MockScenario1";
string scenario2 = "MockScenario2";
MockScenario1.GetInfo();
MockScenario2.GetInfo();
How can I dynamically use the strings to call method name here like
scenario1.GetInfo()
scenario2.GetInfo()
I tried to find out all options by string and control space to find related options. Any suggestions?
I am tried the below and trying to Get class name generated dynamically
The below code generated method name dynamically
string methodName = "hello";
//Get the method information using the method info class
MethodInfo mi = this.GetType().GetMethod(methodName);
//Invoke the method
// (null- no parameter for the method call
// or you can pass the array of parameters...)
mi.Invoke(this, null);
More clear scenario:
I am trying to send class name as parameter
MockScenario1 and MockScenario2 are class names.
string scenarioCats = "MockScenario1";
string scenarioDogs = "MockScenario2";
GetResult(scenarioCats);
GetResult(scenarioDogs);
public static void GetCatsResult(string scenarioCats){
scenarioCats obj = new scenarioCats();
obj.GetInfo();
}
public static void GetDogsResult(string scenarioDogs){
scenarioDogs obj = new scenarioDogs();
obj.GetInfo();
}

How to create an instance of a type from its string representation:
string scenario1 = "TheNamespace.MockScenario1";
Type theType = this.GetType().Assembly.GetType(scenario1);
var theInstance = (MockScenario1)Activator.CreateInstance(theType);
theInstance.GetInfo();
It will be better if your classes implement a common interface, for example IGetInfoAware, and then you could write a more generic loader:
var theInstance = (IGetInfoAware)Activator.CreateInstance(theType);
Note: you need to provide the full class name for scenario1 and scenario2
See Activator.CreateInstance
EDIT:
As #Georg pointed out, if the type is not declared in the assembly of the context objects, then it is necessary first to get the assembly where the type is hosted:
var theAssembly = (
from Assembly assembly in AppDomain.CurrentDomain.GetAssemblies()
where (assembly.FullName == "TheNamespace.AssemblyName")
select assembly
)
.FirstOrDefault();
if ( theAssembly!= null ){
Type theType = theAssembly.GetType(scenario1);
var theInstance = (IGetInfoAware)Activator.CreateInstance(theType);
theInstance.GetInfo();
}
If for some reason the assembly name is unknown to you, then the type could be resolved like the following:
public Type GetTypeFromString(String typeName)
{
foreach (Assembly theAssembly in AppDomain.CurrentDomain.GetAssemblies())
{
Type theType = theAssembly.GetType(typeName);
if (theType != null)
{
return theType;
}
}
return null;
}

You can use reflection:
Type thisType = this.GetType();
MethodInfo theMethod = thisType.GetMethod(FunctionName);
theMethod.Invoke(this, userParameters);

You could use the command design pattern. So you'd use a hash map to store your string as the key in the hash map, and then your function would be the value of the hashmap. Then when you want to call your function you say hashmap.get ("yourString"). This would return the function that you stored as your value and you could call it from there.

I suggest using Dictionary<String, Action>, where you can put down all the scenarios and their names e.g.
private static Dictionary<String, Action> s_Scenario =
new Dictionary<String, Action>() {
{"MockScenario1", () => MockScenario1.GetInfo()},
{"MockScenario2", () => MockScenario2.GetInfo()},
};
...
s_Scenario["MockScenario1"]();
s_Scenario["MockScenario2"]();

Without giving Namespace to GetType() can return null always (I faced with that problem before adding this answer.), so it should be like this;
As you mentioned, you want to give string as parameter
public void GetCatsResult(string scenarioCats)
{
string item = this.GetType().Namespace + "." + scenarioCats;
// combined class string with the namespace
Type className = Type.GetType(item);
// found the class
MethodInfo m = className.GetMethod("GetInfo");
// get the method from class
object value = m.Invoke(null,null);
// invoke and value will represent the return value.
}
Here is my Scenario class,
class Scenario1
{
public static string GetInfo()
{
return "GetInfo() called, Scenario1";
}
}
Result; (btw GetCatsResult() called at Form_Load and given string which declared as string scenario1 = "Scenario1";)
Hope helps,

If it is for testing you can use PrivateObject:
using Microsoft.VisualStudio.TestTools.UnitTesting;
class Class1
{
public Class1()
{
MyClass myClass = new MyClass();
PrivateObject myClassPrivateObject = new PrivateObject(myClass, new PrivateType(typeof(MyClass)));
myClassPrivateObject.Invoke("MyMethod");
}
}

Related

How to pass a dynamic model as 'T' to a C# generic function

I have a generic function which is like below
private List<T> GetAll<T>()
{
var listOfTModels = // gets the list of T from the database.
return listOfTModels;
}
I need to pass the model ( T ) dynamically to this function based on a string which will be decided at runtime.
public void SomeFunction(string modelName)
{
// Call the above Get method with modelName parameter as the 'T'
var listOfModels = GetAll<something>(); //not sure what type this something should be "Type" or "string"
// Further Logic on listOfModels
}
How could this be done?
You will need to use reflection to get the method like so:
typeof(ClassWithGetAll).GetMethod("GetAll",
BindingFlags.Instance | BindingFlags.NonPublic);
This will return a method info which you will then use to create a generic method via MakeGenericMethod.
The only way to get a type from a string name AFAIK is with Type.GetType but you will need a AssemblyQualifiedName for that, so passing in a short/simplified name like string or int or anything like that will more than likely return null.
If you figure out how to either get the qualified name or how to search for the type, the last thing would be to invoke the MethodInfo returned from the MakeGenericMethod call, here is a example of how the code could look:
public void SomeFunction(string modelName)
{
// No idea what the class/struct in which the method "GetAll"
// is called, hence use this name
var instance = new ClassWithGetAll();
//Retrieves the info of "GetAll<T>"
MethodInfo method = typeof(ClassWithGetAll).GetMethod("GetAll",
BindingFlags.Instance | BindingFlags.NonPublic);
//Commented out as you will need to figure out how to get the
// assembly qualified name of the input model name, unless
// it is qualified.
//modelName = GetAssemblyQualifiedName(modelName);
Type modelType = Type.GetType(modelName);
//Creates a generic method: "GetAll<T>" => "GetAll<modelType>"
method = method.MakeGenericMethod(modelType);
//Invokes the newly created generic method in the specified
// instance with null parameters, which returns List<modelType>
object list = method.Invoke(instance, null);
}
I think inheritance would be the right way to solve your problem.
public class TBase
{
public int Prop { get; set; }
}
public class TChildOne : TBase
{
}
public class TChildTwo : TBase
{
}
public class GClass
{
private List<T> GetAll<T>() where T : TBase
{
var listOfTModels = // gets the list of T from the database.
return listOfTModels;
}
public void Main(string strType)
{
switch (strType)
{
case "TChildOne":
{
var child = GetAll<TChildOne>();
break;
}
case "TChildTwo":
{
var child = GetAll<TChildTwo>();
break;
}
default:
throw new Exception("type not found");
}
}
}

C# Cause DLL Dynamic Load Mismatch Intentially

For testing purposes,
I'm trying to construct a scenario in which I have two different dlls with the same namespace, class and method name.
E.g.
DLL1:
namespace SomeNamespace
{
public class Foo
{
public static string Bar()
{
return "A";
}
}
}
DLL2:
namespace SomeNamespace
{
public class Foo
{
public static string Bar()
{
return "B";
}
}
}
I'm trying to write code which dynamically calls Foo.Bar() in order to get exception of ambiguity.
In the code I have I specifically need to pass the dll name as a parameter, which I want to avoid.
Assembly a = Assembly.LoadFile(dllPath);
Type t = a.GetType(typeName);
MethodInfo method = t.GetMethod(methodName);
var result = new object();
if (method.IsStatic)
{
result = method.Invoke(null, null);
}
else
{
object instance = Activator.CreateInstance(t);
result = method.Invoke(instance, null);
}
Is there a way to casue this exception?
If both assemblies have the same assembly name you can use Type.GetType(string) like this: https://stackoverflow.com/a/6465096/613130, so
Type t = Type.GetType("SomeNamespace.Foo,SomeAssembly");
I don't think there is a .NET method to search for a Type in all the loaded assemblies.

How to get MethodInfo for open generic type from MethodInfo of closed type

Assume I have a class like so:
public class MyClass<T>
{
public void Foo(T t)
{
}
}
Now, assume, I have an instance of MyClass<int> and a MethodInfo of its Foo method.
Calling methodInfo.GetParameters() will return a ParameterInfo array with one entry, referring to type int. My problem is, that I can't seem to find out, if that parameter was declared as int in the class or as T.
What am I trying to achieve?
At runtime, I want to read the documentation of the method specified by MethodInfo from the XML Doc file generated by Visual Studio.
For the above defined method, the key looks like this:
<namespace>.MyClass`1.Foo(`0)
The `0 refers to the first generic type parameter of the declaring class. To be able to construct this string, I need to somehow get this information.
But how? MethodInfo doesn't seem to contain that info...
The key seems to be Type.ContainsGenericParameters on the parameter type:
Given
public class MyClass<T>
{
public void Foo(T t)
{
}
public void Bar(int i)
{
}
}
Then
class Program
{
static void Main(string[] args)
{
var obj = new MyClass<int>();
// Closed type
var closedType = obj.GetType();
// Open generic (typeof(MyClass<>))
var openType = closedType.GetGenericTypeDefinition();
// Methods on open type
var fooT = openType.GetMethod("Foo");
var barint = openType.GetMethod("Bar");
// Parameter types
var tInFoo = fooT.GetParameters()[0].ParameterType;
var iInBar = barint.GetParameters()[0].ParameterType;
// Are they generic?
var tInFooIsGeneric = tInFoo.ContainsGenericParameters;
var iInBarIsGeneric = iInBar.ContainsGenericParameters;
Console.WriteLine(tInFooIsGeneric);
Console.WriteLine(iInBarIsGeneric);
Console.ReadKey();
}
}
outputs
True
False
This will obviously need more work for overloads and so on.
Could you get the definition of the generic class through Type.GetGenericTypeDefinition Method and find there the definition for the same method, say, by name (and the signature), and then compare Foo(T t) and Foo(int t):
MyClass<int> c = new MyClass<int>();
Type concreteType = c.GetType();
Console.Write("Concrete type name:");
Console.WriteLine(concreteType.FullName);
Console.WriteLine();
MethodInfo concreteMethod = concreteType.GetMethod("Foo");
if (concreteMethod != null)
{
Console.WriteLine(concreteMethod.Name);
foreach (ParameterInfo pinfo in concreteMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
if (concreteType.IsGenericType)
{
Console.Write("Generic type name:");
Type genericType = concreteType.GetGenericTypeDefinition();
Console.WriteLine(genericType.FullName);
Console.WriteLine();
MethodInfo genericMethod = genericType.GetMethod("Foo");
if (genericMethod != null)
{
Console.WriteLine(genericMethod.Name);
foreach (ParameterInfo pinfo in genericMethod.GetParameters())
{
Console.WriteLine(pinfo.Name);
Console.WriteLine(pinfo.ParameterType);
Console.WriteLine();
}
Console.WriteLine();
}
}
I don't know if you have considered using Mono.Cecil instead of .Net's reflection.
// Gets the AssemblyDefinition (similar to .Net's Assembly).
Type testType = typeof(MyClass<>);
AssemblyDefinition assemblyDef = AssemblyDefinition.ReadAssembly(new Uri(testType.Assembly.CodeBase).LocalPath);
// Gets the TypeDefinition (similar to .Net's Type).
TypeDefinition classDef = assemblyDef.MainModule.Types.Single(typeDef => typeDef.Name == testType.Name);
// Gets the MethodDefinition (similar to .Net's MethodInfo).
MethodDefinition myMethodDef = classDef.Methods.Single(methDef => methDef.Name == "Foo");
then myMethodDef.FullName returns
"System.Void MyNamespace.MyClass`1::Foo(System.Int32,T,System.String)"
and classDef.GenericParameters[0].FullName returns
"T"
Note that Mono.Cecil uses a different way of writing generics, nested classes and arrays:
List[T] => List<T>
MyClass+MyNestedClass => MyClass/MyNestedClass
int[,] => int[0...,0...]
This was a tricky one. If you have a MethodInfo instance of a (non-generic) method, which was obtained on an open generic Type, you can actually use it to repeatedly close the method (i.e., with different generic arguments for the enclosing type).
The key is to use the obscure static function MethodInfo.GetMethodFromHandle(...):
Complete working example:
static class MyType<T>
{
public static int TheMethod() => typeof(T).MetadataToken; // demo method
};
How to use:
static void demo()
{
var Topen = typeof(MyType<>);
var mi_open = Topen.GetMethod("TheMethod"); // can't Invoke() this one...
// ...later perhaps... MyType<ushort>.TheMethod()
var Tclose = Topen.MakeGenericType(typeof(ushort));
var mi = MethodInfo.GetMethodFromHandle(mi_open.MethodHandle, Tclose.TypeHandle);
var ret = (int)mi.Invoke(null, null); // works --> 0x02000150
// later yet... MyType<Guid>.TheMethod(), reusing 'mi_open' (and Topen)...
Tclose = Topen.MakeGenericType(typeof(Guid));
mi = MethodInfo.GetMethodFromHandle(mi_open.MethodHandle, Tclose.TypeHandle);
ret = (int)mi.Invoke(null, null); // works --> 0x020000eb
}
Notice that the Tclose type handle (passed in as the second arg) is not simply the handle of the type argument T that you ultimately want to parametrize with. Rather, you have to use that T to close the original Topen (open) generic type first, and then use the handle for the resulting (closed) generic type.
In other words, you can't close a method without first explicitly closing its generic type.

How to convert un-reference-type Object to actual object

Maybe this question make you confuse ,but please help me
In .NET 4.0 , language C#
I have two project ,one is the library define classes and attribute mark infors for class, one is the project that process reflection of class declared from that library.
The problem is , without make reference to library , I just use reflection-related classes to read assembly and I have to get value of properties that declared in object class.
For example
---In LIB project , named lib.dll
public class MarkAttribute: Attribute
{
public string A{get;set;}
public string B{get;set;}
}
[Mark(A="Hello" B="World")]
public class Data
{
}
---In Reflection project
public void DoIt()
{
string TypeName="Lib.Data";
var asm=Assembly.LoadFrom("lib.dll");
foreach (var x in asm.GetTypes())
{
if (x.GetType().Name=="Data")
{
var obj=x.GetType().GetCustomAttributes(false);
//now if i make reference to lib.dll in the usual way , it is ok
var mark=(Lib.MarkAttribute)obj;
var a=obj.A ;
var b=obj.B ;
//but if i do not make that ref
//how can i get A,B value
}
}
}
any idea appreciated
If you know the names of the properties you could use dynamic instead of reflection:
dynamic mark = obj;
var a = obj.A;
var b = obj.B;
You can retrieve the attribute's properties using reflection as well:
Assembly assembly = Assembly.LoadFrom("lib.dll");
Type attributeType = assembly.GetType("Lib.MarkAttribute");
Type dataType = assembly.GetType("Lib.Data");
Attribute attribute = Attribute.GetCustomAttribute(dataType, attributeType);
if( attribute != null )
{
string a = (string)attributeType.GetProperty("A").GetValue(attribute, null);
string b = (string)attributeType.GetProperty("B").GetValue(attribute, null);
// Do something with A and B
}
You can invoke the getter of the property:
var attributeType = obj.GetType();
var propertyA = attributeType.GetProperty("A");
object valueA = propertyA.GetGetMethod().Invoke(obj, null)
You need to remove many of the GetTypes() calls, since you already have a Type object. Then you can use GetProperty to retrieve the property of the custom attribute.
foreach (var x in asm.GetTypes())
{
if (x.Name=="Data")
{
var attr = x.GetCustomAttributes(false)[0]; // if you know that the type has only 1 attribute
var a = attr.GetType().GetProperty("A").GetValue(attr, null);
var b = attr.GetType().GetProperty("B").GetValue(attr, null);
}
}
var assembly = Assembly.Load("lib.dll");
dynamic obj = assembly.GetType("Lib.Data").GetCustomAttributes(false)[0];
var a = obj.A;
var b = obj.B;

string literal converted to type or namespace for generics c#

I new to c# and I am trying to create a method which takes a string and then it instantiates an object using the string as a type.
public void CreateRepository( string name) {
var repository = new Repository<name>();
}
e.g.
Obviously I get a compiler error but how do I convert my string to a namespace?
You can do it in this way:
public void CreateRepository(string name)
{
var type = Type.GetType(name);
var genericRepositoryType = typeof(Repository<>).MakeGenericType(type);
var repositoryObj = Activator.CreateInstance(genericRepositoryType );
// N.B. repositoryObj variable is System.Object
// but is also an istance of Repository<name>
}

Categories

Resources