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.
Related
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)
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");
}
}
I have two dll files Lets say DataLayer.dll and ProcessLayer.dll. DataLayer.dll has a Class called MyClass like below:
public class MyClass
{
public string name;
public int age;
public string aadhar;
}
and I have refereed DataLayer.dll in second assembly ProcessLayer.dll which has one method with input parameter as MyClass.
using DataLayer;
namespace ProcessLayer
{
public class Process
{
public int GetMyClass(MyClass objMy)
{
return objMy.age;
}
}
}
How can I read all method parameters from ProcessLayer.dll using reflection? I am using
Assembly assembly = Assembly.LoadFile(#"C:\ProcessLayer.dll");
foreach (Type _type in assembly.GetTypes())
{
foreach (var method in _type.GetMethods())
{
var parameters = method.GetParameters();
}
}
and got an error when try to execute method.GetParameters(); statement.
Can you please help me ?
how to get it with Mono.cecil any idea?
You need to load the assembly, then get the types, then get the methods for the type you are after.
var myAssembly Assembly.LoadFrom(#"..\ProcessLayer.dll");
var myAssemblyTypes = myAssembly.GetTypes();
var firstType = myAssemblyTypes[0];
var firstTypeMethods = firstType.GetMethods();
var firstTypeFirstMethod = firstTypeMethods[0];
var params = firstTypeFirstMethod.GetParameters();
If you need a type from another assembly, then you can load this in, you may need to instantiate it too.
Assembly assembly = Assembly.LoadFrom("Assembly.LoadFile(#"..\DataLayer.dll");
Type missingType = assembly.GetType(<your missing type>);
var createTypeInstance = Activator.CreateInstance(missingType);
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.
I have the following test class:
public class OutsideClass
{
private List<Type> _interfaces = null;
public void InjectInterfaces(Type[] types)
{
if(_interfaces == null)
{
_interfaces = new List<Type>();
}
foreach (var type in types)
{
if(type.IsInterface)
{
_interfaces.Add(type);
}
}
}
public void PerformSomethingWithTheInterfaces()
{
foreach (var i in _interfaces)
{
new Test<i>().PerformSomething(); // On this line the error occurs
}
}
}
internal class Test<T>
{
internal void PerformSomething()
{
}
}
This gives me on however the message Type or namespace name expected. How can I adjust this code so that it works?
What I am trying to do is to pass in a bunch of interfaces to a class library, there loop over the interfaces and use Unity to Resolve, based on the interface, something. I use the Resolve extension method.
You'd need to use reflection... something like this:
foreach (Type type in _interfaces)
{
Type concreteType = typeof(Test<>).MakeGenericType(new Type[] { type });
MethodInfo method = concreteType.GetMethod("PerformSomething",
BindingFlags.Instance | BindingFlags.NonPublic);
object instance = Activator.CreateInstance(concreteType);
method.Invoke(instance, null);
}
(You may need to make minor changes - the above isn't tested or even compiled.)
With C# 4 and dynamic typing, you can make it somewhat simpler:
foreach (Type type in _interfaces)
{
Type concreteType = typeof(Test<>).MakeGenericType(new Type[] { type });
dynamic d = Activator.CreateInstance(concreteType);
d.PerformSomething();
}
You cannot pass values as generic arguments. Only types. To be clear:
typeof(string) != string.
I don't think this can work. You specialize a generic statically on the type name. You can't pass in a reference to the Type object.
There are ways to do what you want, but they involve C# 4 and DynamicObject.
You might really want to look at C# 4's MEF just as an idea as a unity replacement I think it stands up really well myself and simplifies the resolution mechanisms a lot, and may give functionality to complete the task you're attempting more simply..
namespace MEF_Interface
{
// Interface to recognize the concrete implementation as
public interface IMessageWriter
{
void WriteMessage();
}
}
namespace MEF_HelloMessageWriter
{
// Concrete implementation in another assembly
[Export(typeof(IMessageWriter))]
public class HelloMessageWriter : IMessageWriter
{
public void WriteMessage() { Console.WriteLine("Hello!"); }
}
}
namespace MEF_GoodbyeMessageWriter
{
// Concrete implementation in another assembly
[Export(typeof(IMessageWriter))]
public class GoodbyeMessageWriter : IMessageWriter
{
public void WriteMessage() { Console.WriteLine("Goodbye!"); }
}
}
namespace MEF_Example
{
class DIContainer
{
[Import]
public IMessageWriter MessageWriter { get; set; }
public DIContainer(string directory)
{
// No more messy XML DI definition, just a catalog that loads
// all exports in a specified directory. Filtering is also available.
DirectoryCatalog catalog = new DirectoryCatalog(directory);
catalog.Refresh();
var container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
}
class Program
{
static void Main(string[] args)
{
string helloMessageWriterPath =
#"C:\shared\Projects\MEF_Example\MEF_HelloMessageWriter\bin\Debug";
string goodbyeMessageWriterPath =
#"C:\shared\Projects\MEF_Example\MEF_GoodbyeMessageWriter\bin\Debug";
DIContainer diHelloContainer = new DIContainer(helloMessageWriterPath);
diHelloContainer.MessageWriter.WriteMessage();
DIContainer diGoodbyeContainer = new DIContainer(goodbyeMessageWriterPath);
diGoodbyeContainer.MessageWriter.WriteMessage();
Console.ReadLine();
}
}
}