I'm using the following code to load an assembly at runtime and then get a reference to a specific method and obviously execute it at the end:
var assemblyLoaded = Assembly.LoadFile(absolutePath);
var type = assemblyLoaded.GetType("CreateContactPlugin.Plugin");
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Execute", new Type[] { typeof(System.String)});
if (methodInfo == null)
{
throw new Exception("No such method exists.");
}
Here is the assembly that I'm calling
namespace CreateContactPlugin
{
public class Plugin
{
static bool Execute(string contactName){
bool contactCreated = false;
if (!String.IsNullOrWhiteSpace(contactName))
{
//process
}
return contactCreated;
}
}
}
I can succesfully load the Assembly, the Type. When I highlight the type variable, I see the method listed in the DeclaredMethods array. But when I try to get the Method, it returns always null.
Does somebody see what I might be doing wrong here ?
There's a couple of problems here. First of all the Execute method is static and not public so you need to specify the correct binding flags to get at it.
var methodInfo = type.GetMethod("Execute", BindingFlags.Static | BindingFlags.NonPublic);
However, an alternative (and preferable in my opinion) solution using less reflection and strong typing would be to make your plugin class implement a common interface, that way you can strongly type your instance object. First make a class library with the relevant interfaces in it, for example:
public interface IContactPlugin
{
bool Execute(string contactName);
}
Now your plugin can also reference the same library and becomes this:
namespace CreateContactPlugin
{
public class Plugin : IContactPlugin
{
public bool Execute(string contactName)
{
//snip
}
}
}
And your calling code would now be this:
var assemblyLoaded = Assembly.LoadFile(absolutePath);
var type = assemblyLoaded.GetType("CreateContactPlugin.Plugin");
var instance = Activator.CreateInstance(type) as IContactPlugin;
if (instance == null)
{
//That type wasn't an IContactPlugin, do something here...
}
instance.Execute("name of contact");
The problem is "static" of
static bool Execute(string contactName)
put it as
public bool Execute(string contactName)
Related
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");
}
}
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.
I'm trying to convert my AutoMapper code to be more fluent-api like, e.g.
existing code:
Model.Foo target = Mapper.Map<Contract.Foo, Model.Foo>(source);
What I'd like the code to look like is this
Model.Foo target = source.ConvertTo<Model.Foo>();
I started writing my extension method, but I can't seem to get this to work.
public static class AutoMapperConverterExtension
{
public static T ConvertTo<T>(this string source) where T : new()
{
Type sourceType = Type.GetType(source);
if (IsMapExists<sourceType, T>()) // complains here! cannot resolve 'sourceType'. If I use inline, won't compile.
{
return Mapper.Map<T>(source);
}
throw new NotImplementedException("type not supported for conversion");
}
public static bool IsMapExists<TSource, TDestination>()
{
return (AutoMapper.Mapper.FindTypeMapFor<TSource, TDestination>() != null);
}
}
It looks like you are over-complicating things, and you might be able to get away with:
public static T ConvertTo<T>(this object source)
{
return Mapper.Map<T>(source);
}
That said, you can't use generics as you are attempting to do in the code code as posted. sourceType is a runtime variable, and cannot be used for a generic type argument, which is determined at compile time. In this particular case, AutoMapper provides a non-generic version of FindTypeMapFor() that you can use.
You also cannot assume that source is going to be a string parameter. You probably want an object.
public static T ConvertTo<T>(this object source) where T : new()
{
Type sourceType = Type.GetType(source);
if (IsMapExists(sourceType, typeof(T)))
{
return Mapper.Map<T>(source);
}
throw new NotImplementedException("type not supported for conversion");
}
public static bool IsMapExists(Type source, Type destination)
{
return (AutoMapper.Mapper.FindTypeMapFor(source, destination) != null);
}
The line throwing the error needs to change to use reflection when calling the generic function.
var method = typeof(AutoMapperConverterExtension).GetMethod("IsMapExists");
var generic = method.MakeGenericMethod(sourceType, typeof(T));
bool exists = Convert.ToBoolean(generic.Invoke(null, null));
if (exists)
{
return Mapper.Map<T>(source);
}
How do I use reflection to call a generic method?
I'm using nBuilder to generate some Testdata for my application.
First I tested it and it worked fine.
An easy Example:
Customer customer = Builder<Customer>
.CreateNew()
.Build();
Creates a Object and fills all Properties automatically.
By Example, if customer Contains the attribute: name, it will fill it with name1
and so on...
Well all this works fine, but I have troubles to do that whole thing dynamically now.
What I'm doing now, is Reflection, I'm iterating through all Entities in my Class and foreach of them there should be generated some Testdata, even lookups and childlists should be filled, but thats not a problem.. My question is, how I'm using the above code with any type?
ANYTYPE object = Builder<ANYTYPE> ...
What I tried:
object entity = null; //The object/Entity
Assembly assembly = Assembly.GetAssembly(typeof(EMI_ERPContext)); //Getting Assembly
Type type = assembly.GetType(entityName); //I know the Type
//entity = Activator.CreateInstance(type); Do I must create an Instance here?
object entity = Builder<dynamic> //The above code.. Tried to put dynamic as Type, but doesnt work
.CreateNew()
.Build();
I tested with a console app (complete here), faking the classes / interfaces / methods of nBuilder.
So this works, but not tried in real context.
The method you could reuse is "TryToReflectBuilder". It could be much less verbose, but I let the "Step by step" code, as it's probably more explicit. ReflectionConsole.Test is used as the "entity to reflect".
namespace ReflectionConsole {
class Program {
static void Main(string[] args)
{
object test = TryToReflectBuilder("ReflectionConsole.Test");
Console.ReadKey();
}
public static object TryToReflectBuilder(string type)
{
//getting the assembly : not same as your way, but... that wasn't a problem for you
var assembly = Assembly.GetAssembly(typeof(Test));
//getting the entityType by name.
var entityType = assembly.GetType(type);
//The interesting (I hope) part is starting (yeah)
//get the Builder<T> type
var builderClassType = typeof(Builder<>);
//create generic argument for Builder<T> will take the type of our entity (always an array)
Type[] args = {entityType};
//pass generic arguments to Builder<T>. Which becomes Builder<entityType>
var genericBuilderType = builderClassType.MakeGenericType(args);
//create a new instance of Builder<entityType>
var builder = Activator.CreateInstance(genericBuilderType);
//retrieve the "CreateNew" method, which belongs to Builder<T> class
var createNewMethodInfo = builder.GetType().GetMethod("CreateNew");
//invoke "CreateNew" from our builder instance which gives us an ObjectBuilder<T>, so now an ObjectBuilder<entityType> (well as an ISingleObjectBuilder<entityType>, but... who minds ;))
var objectBuilder = createNewMethodInfo.Invoke(builder, null);
//retrieve the "Build" method, which belongs to ObjectBuilder<T> class
var buildMethodInfo = objectBuilder.GetType().GetMethod("Build");
//finally, invoke "Build" from our ObjectBuilder<entityType> instance, which will give us... our entity !
var result = buildMethodInfo.Invoke(objectBuilder, null);
//it would be sad to return nothing after all these efforts, no ??
return result;
}
}
public class Builder<T>
{
public static ISingleObjectBuilder<T> CreateNew()
{
Console.WriteLine(string.Format("{0} creating new",typeof(T)));
return new ObjectBuilder<T>();
}
}
public interface ISingleObjectBuilder<T> : IBuildable<T>
{
}
public interface IObjectBuilder<T> : ISingleObjectBuilder<T>
{
}
public interface IBuildable<T>
{
T Build();
}
public class ObjectBuilder<T> : ISingleObjectBuilder<T>
{
public T Build()
{
Console.WriteLine(string.Format("{0} building myself", typeof(T)));
return Activator.CreateInstance<T>();
}
}
public class Test
{
}
}
I am using reflection to invoke a method from another dll.That method takes a class object as input. How can i call that method.
I tried copying the same class to both dlls and i created an object of that class and passed it. It throws invliad conversion error in complie time itself.
Then i tried to let the function take an object as argument and then tried to cast it to the required class. It is throwing invalid cast exception in runtime.
this is what i tried
Test objTest = new Test("name","type");
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
object[] args = { objTest };
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
In the second dll the method is like
public string MyFunction(Test obj)
My problem is that Class Test is in
the other assembly(the classes are in
two different assemblies)
You have a bit of a design problem. You have an assembly (let's call it assembly A) containing the sample reflection code that you posted. You also have a second assembly (let's call it assembly B) that contains MyClass and Test.
The issue is that in your reflection code you are attempting to create an instance of the Test class so that you can pass it as a parameter to MyClass.MyFunction.
You mentioned that you copied the source code for the Test class into assembly A; that will not work. What you've done there is essentially create two different classes with the same name and same structure. Since the two classes are not the same as far as the CLR is concerned, you will get an invalid cast exception if you try to cast one to the other.
Given what you've posted so far, it seems to me that the most straightforward solution for your approach is to have a third assembly (let's call it assembly C) that contains components that are known to both assemblies A and B. Create a class library project in your solution, move the Test class into that project, get rid of any other occurrences of the Test class in the first two projects, and add references in both of the first two projects referencing the new project. Once you've done that, both assembly A and assembly B will be referencing the same class definition for the Test class and the sample code that you've posted will work.
Let me point out something, though. If the code in assembly A doesn't know enough about the code in assembly B in order to instantiate MyClass and call MyFunction directly (rather than through reflection), then how does it know enough about that code to know what parameters to pass? Does MyFunction have a common method signature that assembly A understands? If that's the case, then MyClass should probably implement an interface that assembly A knows about so that assembly A can invoke MyFunction directly, as shown below:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
IMyInterface instance = Activator.CreateInstance(dllType) as IMyInterface;
if (instance != null) // check if this object actually implements the IMyInterface interface
{
instance.MyFunction(objTest);
}
}
If that doesn't seem like an approach that you want, then there are other options. Since it seems like you don't want for assembly A to have a direct reference to assembly B, if you keep the Test class inside of assembly B, then there isn't any way for assembly A to have any knowledge of the Test class in order to construct one. In that case, you could use a factory pattern approach, basically so that assembly A knows of some kind of factory object that is capable of instantiating a Test object. Below is an example of an implementation:
I mentioned above about creating a third project. I would still recommend doing so. In my example, I've named mine "MyProject.Common". It contains the following code:
// define a simple factory interface
public interface IFactory
{
object CreateInstance();
}
// and a generic one (hey, why not?)
public interface IFactory<T> : IFactory
{
new T CreateInstance();
}
// define a Factory attribute that will be used to identify the concrete implementation of a factory
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface | AttributeTargets.Parameter, AllowMultiple = false, Inherited = true)]
public class FactoryAttribute : Attribute
{
public Type FactoryType { get; set; }
public FactoryAttribute(Type factoryType)
{
this.FactoryType = factoryType;
}
}
The IFactory interfaces and the Factory attribute will be known and understood by the other projects in my solution, since they both reference the MyProject.Common project.
Below is the code contained within my "MyProject.Components" project:
public class Test
{
public string Name { get; set; }
public string Type { get; set; }
public Test(string name, string type)
{
this.Name = name;
this.Type = type;
}
}
public class TestFactory : IFactory<Test>
{
#region IFactory<Test> Members
public Test CreateInstance()
{
return new Test("name", "type");
}
#endregion
#region IFactory Members
object IFactory.CreateInstance()
{
return this.CreateInstance();
}
#endregion
}
public class MyClass
{
// the Factory attribute on the first parameter indicates that the class TestFactory
// should be used as a factory object to construct the argument for this method
public string MyFunction([Factory(typeof(TestFactory))]Test obj)
{
if (obj == null)
return null;
else
return obj.ToString();
}
}
Finally, I've replaced the original reflection code that you posted with the following:
Assembly assembly = Assembly.Load("MyProject.Components");
Type dllType = assembly.GetType("MynameSpace.MyClass");
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
// use the parameter information to construct the arguments
ParameterInfo[] parameters = m.GetParameters();
object[] args;
if (parameters != null && parameters.Length > 0)
{
args = new object[parameters.Length];
for (int i = 0; i < parameters.Length; i++)
{
// check for factory attributes on the actual parameter
FactoryAttribute[] attributes = parameters[i].GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found, check the parameter type for factory attributes
if (attributes == null || attributes.Length == 0)
attributes = parameters[i].ParameterType.GetCustomAttributes(typeof(FactoryAttribute), true) as FactoryAttribute[];
// if no attributes were found still, then give up
if (attributes == null || attributes.Length == 0)
{
// this parameter has no factory specified,
// so how would this code know how to create the argument for that parameter ???
args[i] = null;
continue; // move on to the next parameter
}
// there should only be one factory attribute, so use the first one
// assumption made here is that all factory classes will have a parameterless constructor
IFactory factory = Activator.CreateInstance(attributes[0].FactoryType) as IFactory;
args[i] = factory.CreateInstance();
}
}
else
// there are no parameters
args = null;
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
If you mean by class object an object that is a Type object then you can just pass the type of the object as the parameter...e.g.
object[] args = {typeof(typeneeded)};
or
object[] args = { assembly.GetType(typeneeded) };
MethodInfo.Invoke() is declared as the following:
public Object Invoke(
Object obj,
Object[] parameters
)
The first parameter specifies the object to work on, the second one specifies the parameters for the function.
I replicated your code in LINQPad, and this works fine:
void Main()
{
string strReturnValue = "";
Test objTest = new Test("name","type");
Type dllType = typeof(MyClass);
if (dllType != null)
{
MethodInfo m = dllType.GetMethod("MyFunction");
object objdll;
objdll = Activator.CreateInstance(dllType);
object[] args = { objTest };
if ((m != null))
{
strReturnValue += (string)m.Invoke(objdll, args);
}
}
}
public class Test
{
public Test(string s1, string s2)
{
}
}
public class MyClass
{
public string MyFunction(Test t)
{
return "";
}
}
You will have to load the Test object the same way you load the MyClass instance, and as Test requires parameters in the constructor, you'll have to use a ConstructorInfo:
Assembly assembly = Assembly.Load(); //assembly of "Test"
Type testType = assembly.GetType("Test");
ConstructorInfo ci = testType.GetConstructor(
BindingFlags.Public | BindingFlags.Instance,
null,
new Type[]{typeof(string), typeof(string)},
null);
Test objTest = ci.Invoke(new object[] { "name", "type" });
now you can use objTest in the code.