I have several static classes in the namespace mySolution.Macros such as
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
So my question is how it will be possible to call those methods with the help of reflection?
If the methods where NOT to be static then I could do something like:
var macroClasses = Assembly.GetExecutingAssembly().GetTypes().Where( x => x.Namespace.ToUpper().Contains("MACRO") );
foreach (var tempClass in macroClasses)
{
var curInsance = Activator.CreateInstance(tempClass);
// I know have an instance of a macro and will be able to run it
// using reflection I will be able to run the method as:
curInsance.GetType().GetMethod("Run").Invoke(curInsance, null);
}
I will like to keep my classes static. How will I be able to do something similar with static methods?
In short I will like to call all the Run methods from all the static classes that are in the namespace mySolution.Macros.
As the documentation for MethodInfo.Invoke states, the first argument is ignored for static methods so you can just pass null.
foreach (var tempClass in macroClasses)
{
// using reflection I will be able to run the method as:
tempClass.GetMethod("Run").Invoke(null, null);
}
As the comment points out, you may want to ensure the method is static when calling GetMethod:
tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
You could really, really, really optimize your code a lot by paying the price of creating the delegate only once (there's also no need to instantiate the class to call an static method). I've done something very similar, and I just cache a delegate to the "Run" method with the help of a helper class :-). It looks like this:
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
static class MacroRunner {
static MacroRunner() {
BuildMacroRunnerList();
}
static void BuildMacroRunnerList() {
macroRunners = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Namespace.ToUpper().Contains("MACRO"))
.Select(t => (Action)Delegate.CreateDelegate(
typeof(Action),
null,
t.GetMethod("Run", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Action> macroRunners;
public static void Run() {
foreach(var run in macroRunners)
run();
}
}
It is MUCH faster this way.
If your method signature is different from Action you could replace the type-casts and typeof from Action to any of the needed Action and Func generic types, or declare your Delegate and use it. My own implementation uses Func to pretty print objects:
static class PrettyPrinter {
static PrettyPrinter() {
BuildPrettyPrinterList();
}
static void BuildPrettyPrinterList() {
printers = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Name.EndsWith("PrettyPrinter"))
.Select(t => (Func<object, string>)Delegate.CreateDelegate(
typeof(Func<object, string>),
null,
t.GetMethod("Print", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Func<object, string>> printers;
public static void Print(object obj) {
foreach(var printer in printers)
print(obj);
}
}
Class that will call the methods:
namespace myNamespace
{
public class myClass
{
public static void voidMethodWithoutParameters()
{
// code here
}
public static string stringReturnMethodWithParameters(string param1, string param2)
{
// code here
return "output";
}
}
}
Calling myClass static methods using Reflection:
var myClassType = Assembly.GetExecutingAssembly().GetType(GetType().Namespace + ".myClass");
// calling my void Method that has no parameters.
myClassType.GetMethod("voidMethodWithoutParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
// calling my string returning Method & passing to it two string parameters.
Object methodOutput = myClassType.GetMethod("stringReturnMethodWithParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { "value1", "value1" });
Console.WriteLine(methodOutput.ToString());
Note: I don't need to instantiate an object of myClass to use it's methods, as the methods I'm using are static.
Great resources:
How C# Reflection Works
MethodBase.Invoke Method
I prefer simplicity...
private void _InvokeNamespaceClassesStaticMethod(string namespaceName, string methodName, params object[] parameters) {
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
try {
if((_t.Namespace == namespaceName) && _t.IsClass) _t.GetMethod(methodName, (BindingFlags.Static | BindingFlags.Public))?.Invoke(null, parameters);
} catch { }
}
}
}
Usage...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");
But in case you're looking for something a little more robust, including the handling of exceptions...
private InvokeNamespaceClassStaticMethodResult[] _InvokeNamespaceClassStaticMethod(string namespaceName, string methodName, bool throwExceptions, params object[] parameters) {
var results = new List<InvokeNamespaceClassStaticMethodResult>();
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
if((_t.Namespace == namespaceName) && _t.IsClass) {
var method_t = _t.GetMethod(methodName, parameters.Select(_ => _.GetType()).ToArray());
if((method_t != null) && method_t.IsPublic && method_t.IsStatic) {
var details_t = new InvokeNamespaceClassStaticMethodResult();
details_t.Namespace = _t.Namespace;
details_t.Class = _t.Name;
details_t.Method = method_t.Name;
try {
if(method_t.ReturnType == typeof(void)) {
method_t.Invoke(null, parameters);
details_t.Void = true;
} else {
details_t.Return = method_t.Invoke(null, parameters);
}
} catch(Exception ex) {
if(throwExceptions) {
throw;
} else {
details_t.Exception = ex;
}
}
results.Add(details_t);
}
}
}
}
return results.ToArray();
}
private class InvokeNamespaceClassStaticMethodResult {
public string Namespace;
public string Class;
public string Method;
public object Return;
public bool Void;
public Exception Exception;
}
Usage is pretty much the same...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);
Related
I have several static classes in the namespace mySolution.Macros such as
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
So my question is how it will be possible to call those methods with the help of reflection?
If the methods where NOT to be static then I could do something like:
var macroClasses = Assembly.GetExecutingAssembly().GetTypes().Where( x => x.Namespace.ToUpper().Contains("MACRO") );
foreach (var tempClass in macroClasses)
{
var curInsance = Activator.CreateInstance(tempClass);
// I know have an instance of a macro and will be able to run it
// using reflection I will be able to run the method as:
curInsance.GetType().GetMethod("Run").Invoke(curInsance, null);
}
I will like to keep my classes static. How will I be able to do something similar with static methods?
In short I will like to call all the Run methods from all the static classes that are in the namespace mySolution.Macros.
As the documentation for MethodInfo.Invoke states, the first argument is ignored for static methods so you can just pass null.
foreach (var tempClass in macroClasses)
{
// using reflection I will be able to run the method as:
tempClass.GetMethod("Run").Invoke(null, null);
}
As the comment points out, you may want to ensure the method is static when calling GetMethod:
tempClass.GetMethod("Run", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
You could really, really, really optimize your code a lot by paying the price of creating the delegate only once (there's also no need to instantiate the class to call an static method). I've done something very similar, and I just cache a delegate to the "Run" method with the help of a helper class :-). It looks like this:
static class Indent{
public static void Run(){
// implementation
}
// other helper methods
}
static class MacroRunner {
static MacroRunner() {
BuildMacroRunnerList();
}
static void BuildMacroRunnerList() {
macroRunners = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Namespace.ToUpper().Contains("MACRO"))
.Select(t => (Action)Delegate.CreateDelegate(
typeof(Action),
null,
t.GetMethod("Run", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Action> macroRunners;
public static void Run() {
foreach(var run in macroRunners)
run();
}
}
It is MUCH faster this way.
If your method signature is different from Action you could replace the type-casts and typeof from Action to any of the needed Action and Func generic types, or declare your Delegate and use it. My own implementation uses Func to pretty print objects:
static class PrettyPrinter {
static PrettyPrinter() {
BuildPrettyPrinterList();
}
static void BuildPrettyPrinterList() {
printers = System.Reflection.Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => x.Name.EndsWith("PrettyPrinter"))
.Select(t => (Func<object, string>)Delegate.CreateDelegate(
typeof(Func<object, string>),
null,
t.GetMethod("Print", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public)))
.ToList();
}
static List<Func<object, string>> printers;
public static void Print(object obj) {
foreach(var printer in printers)
print(obj);
}
}
Class that will call the methods:
namespace myNamespace
{
public class myClass
{
public static void voidMethodWithoutParameters()
{
// code here
}
public static string stringReturnMethodWithParameters(string param1, string param2)
{
// code here
return "output";
}
}
}
Calling myClass static methods using Reflection:
var myClassType = Assembly.GetExecutingAssembly().GetType(GetType().Namespace + ".myClass");
// calling my void Method that has no parameters.
myClassType.GetMethod("voidMethodWithoutParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, null);
// calling my string returning Method & passing to it two string parameters.
Object methodOutput = myClassType.GetMethod("stringReturnMethodWithParameters", BindingFlags.Public | BindingFlags.Static).Invoke(null, new object[] { "value1", "value1" });
Console.WriteLine(methodOutput.ToString());
Note: I don't need to instantiate an object of myClass to use it's methods, as the methods I'm using are static.
Great resources:
How C# Reflection Works
MethodBase.Invoke Method
I prefer simplicity...
private void _InvokeNamespaceClassesStaticMethod(string namespaceName, string methodName, params object[] parameters) {
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
try {
if((_t.Namespace == namespaceName) && _t.IsClass) _t.GetMethod(methodName, (BindingFlags.Static | BindingFlags.Public))?.Invoke(null, parameters);
} catch { }
}
}
}
Usage...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run");
But in case you're looking for something a little more robust, including the handling of exceptions...
private InvokeNamespaceClassStaticMethodResult[] _InvokeNamespaceClassStaticMethod(string namespaceName, string methodName, bool throwExceptions, params object[] parameters) {
var results = new List<InvokeNamespaceClassStaticMethodResult>();
foreach(var _a in AppDomain.CurrentDomain.GetAssemblies()) {
foreach(var _t in _a.GetTypes()) {
if((_t.Namespace == namespaceName) && _t.IsClass) {
var method_t = _t.GetMethod(methodName, parameters.Select(_ => _.GetType()).ToArray());
if((method_t != null) && method_t.IsPublic && method_t.IsStatic) {
var details_t = new InvokeNamespaceClassStaticMethodResult();
details_t.Namespace = _t.Namespace;
details_t.Class = _t.Name;
details_t.Method = method_t.Name;
try {
if(method_t.ReturnType == typeof(void)) {
method_t.Invoke(null, parameters);
details_t.Void = true;
} else {
details_t.Return = method_t.Invoke(null, parameters);
}
} catch(Exception ex) {
if(throwExceptions) {
throw;
} else {
details_t.Exception = ex;
}
}
results.Add(details_t);
}
}
}
}
return results.ToArray();
}
private class InvokeNamespaceClassStaticMethodResult {
public string Namespace;
public string Class;
public string Method;
public object Return;
public bool Void;
public Exception Exception;
}
Usage is pretty much the same...
_InvokeNamespaceClassesStaticMethod("mySolution.Macros", "Run", false);
I am trying a demo for reflection. The assembly I want to reflect in this class goes something like this
namespace DelegatesSampleApplication
{
delegate bool IsPromotable (Employee employee); // Declaration Syntax is similar to that of a method's
class Program
{
public static void Main(string[] args)
{
//code goes here
}
}
class Employee
{
public int EmployeeId { get; set; }
public string EmployeeName { get; set; }
public int Salary { get; set; }
public int Experience { get; set; }
public void PromoteEmployees(List<Employee> employeeList, IsPromotable isPromotableObj)
{
/*foreach (Employee employee in employeeList)
{
if (employee.Experience >= 5 && employee.Salary >= 10000) //That's a hard-coded logic that you have developed as a Framework Developer which makes the class itself not reusable
{
Console.WriteLine(" {0} will be promoted in the next R.P. Cycle ", employee.EmployeeName);
}
}
Console.ReadKey();*/
foreach (Employee employee in employeeList)
{
if (isPromotableObj(employee))
{
Console.WriteLine(" {0} will be promoted in the next R.P. Cycle ", employee.EmployeeName);
}
}
Console.ReadKey();
}
}
}
Now the problem I am facing is, I am trying to read from this assembly in my program and trying to invoke the delegate which takes in a class instance as a parameter.
What I am doing is something like this in a different class altogether
namespace ReflectionSample
{
delegate bool empIsPromotable (Object obj);
class Program
{
static void Main(string[] args)
{
Console.WriteLine("***************Loading External assembly*************");
Assembly assembly = Assembly.LoadFrom(#"C:\Users\Chiranjib\Documents\visual studio 2012\Projects\DelegatesSampleApplication\DelegatesSampleApplication\bin\Debug\DelegatesSampleApplication.exe");
Type employeeType = assembly.GetType("DelegatesSampleApplication.Employee"); //Gets the System.Type object for the Employee Class from the just loaded assembly with all it's dependencies
Console.WriteLine("***************Loading External assembly properties*************");
//Setting properties here
Console.WriteLine("***************Creating an array list that will hold these employee instances***************");
List<Object> employeeInstanceList = new List<object>();
employeeInstanceList.Add(employeeInstance);
employeeInstanceList.Add(employeeInstance2);
Console.WriteLine("***************Invoking External assembly methods*************");
var args = new Object[] {
new List<employeeType>(),
(((employeeInstance) => { return true; }))
};
Console.ReadKey();
}
}
}
This throws error. Saying employeeType missing an assembly reference. Also I cannot convert a lambda expression into an object. I cannot directly type cast to (IsPromotable) right ? I am using reflection. So I am supposed not to have a direct access.
How would I be able to access the delegate via reflection ?
Please help me through. Thanks in advance.
IsPromotable is not invokeable, it's simply a delegate definition. Think of it like an interface. It just tells you what the method takes and returns, but does not actually do anything.
You can call PromoteEmployees like this:
PromoteEmployees(new List<Employee>, (employee) => { return employee.Name == "Rob"; });
Any method which matches the signature of IsPromotable is a valid parameter to the method (ie, any method that takes an Employee and returns a bool). Could you elaborate a bit more on what you're trying to do, exactly?
If you just want a list of delegates, you can do this:
GetType().Assembly.GetTypes().Where(t => t.IsSubClassOf(typeof(BaseDelegate)));
Note; this will only return the delegates in your current assembly. You might want to change it to:
typeof(Employee).GetTypes().Assembly.Where(t => t.IsSubClassOf(typeof(BaseDelegate)));
To get all methods in an assembly which are castable to IsPromotable, you can do this:
var delegateMethod = typeof(IsPromotable).GetMethod("Invoke");
var #params = delegateMethod.GetParameters();
var returnType = delegateMethod.ReturnType;
var matchingMethods = typeof(IsPromotable)
.Assembly
.GetTypes()
.SelectMany(t => t.GetMethods())
.Where(m => {
if (m.ReturnType != returnType)
return false;
var currParams = m.GetParameters();
if (currParams.Length != #params.Length)
return false;
for(var i = 0; i < currParams.Length;i++)
if (currParams[i] != #params[i])
return false;
return true;
});
To invoke the method with reflection, you can do this:
var args = new Object[] {
new List<Employee>(),
((IsPromotable)((emp) => { return true; }))
};
var value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, args);
Or, you can just pass it a regular method:
var args = new Object[] {
new List<Employee>(),
((IsPromotable)Test)
};
var value = employeeType.InvokeMember("PromoteEmployees", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public, null, employeeInstance, args);
With the method:
private bool Test(Employee emp)
{
return false;
}
I've got a class, which has three overloaded methods. Let's say, there is:
class MyChildClass
{
public void myMethod(int i)
{ /* do something with i */ }
public void myMethod(int a, string b)
{ /* get i from a and b and call: */ myMethod(i); }
public void myMethod(string c, string d)
{ /* get i from c and d and call: */ myMethod(i); }
}
Now I'd like this class to be a private field in other (parent) class, but I need those three methods to be accessible. For now, I just did:
class MyBaseClass
{
private MyChildClass myObject = new myChildClass(); // or similar
public void myMethod(int i)
{ myObject.myMethod(i); }
public void myMethod(int a, string b)
{ myObject.myMethod(a, b); }
public void myMethod(string c, string s)
{ myObject.myMethod(c, d); }
}
Is there a way to implement it as one short method? Something which would look like:
public void myMethod(unknownListOfArgumentsOfDifferentTypes args)
{ myObject.myMethod(args); }
I tried to use public void myMethod(params object[] something) but it didn't work. Is it possible, or do I have to "project" every method into another?
EDIT: Child class has various methods and fields, which I want to be accessible for parent class only. That's why I don't want parent to derive after it. I didn't explain that, sorry if it looked like child class contains only those three methods. Those are the methods I want to be accessible as public methods of parent class.
Why don't you do
class MyChildClass : MyBaseClass
{
}
same effect, less code, and this way MyChildClass is a MyBaseClass
If you implement some sort of generic facade using reflection you'll just be reducing performance, bypassing the benefits of type safety and delaying the discovery of problems.
You'll also have have a "has a" relationship instead "is a" relationship which is incongruent with your class names.
If you want to give up this simplicty with its associated benefits you could make use the GetMethodBySig extension accepted in this post.
Something like this,
class SemiGenericFacade<T> where T : new()
{
private readonly t = new T();
public void CallVoidOnT(string name, params object[] parameters)
{
var paramTypes = parameters.Select(p => typeof(p))
var match = typeof(T).GetMethodBySig(typeof(void), paramTypes)
.Single(mi => mi.Name == name);
match.Invoke(this.t, parameters);
}
}
Following on from Piotr Justyna's comment, implementing and using this method results in the cat turning into a tiger and eating her kittens.
If you were to do this it would make sense to add to the linked extension
public static class Extensions
{
public static MethodInfo GetMethodByNameThenSig(
this Type type,
string name,
Type returnType,
params Type[] parameterTypes)
{
return type.GetMethods().Where((m) =>
{
if (m.Name != name)
{
return false;
}
if (m.ReturnType != returnType)
{
return false;
}
var parameters = m.GetParameters();
if ((parameterTypes == null || parameterTypes.Length == 0))
{
return parameters.Length == 0;
}
if (parameters.Length != parameterTypes.Length)
{
return false;
}
for (int i = 0; i < parameterTypes.Length; i++)
{
if (parameters[i].ParameterType != parameterTypes[i])
{
return false;
}
}
return true;
}).Single();
}
}
Which you could use like this,
class GenericFacade<T> where T : new()
{
private readonly t = new T();
public void CallOnInternal(string name, params object[] parameters)
{
var paramTypes = parameters.Select(p => typeof(p))
var match = typeof(T).GetMethodByNameThenSig(
name,
typeof(void),
paramTypes);
match.Invoke(this.t, parameters);
}
public TResult CallOnInternal<TResult>(string name, params object[] parameters)
{
var paramTypes = parameters.Select(p => typeof(p))
var match = typeof(T).GetMethodByNameThenSig(
name,
typeof(TResult),
paramTypes);
return (TResult)match.Invoke(this.t, parameters);
}
}
FINAL EDIT
Looking at the code involved to use reflection and considering the cost associated with the loss of type safety. I'd suggest its better to establish the "has-a" relationship explicitly in the traditional manner.
You can use public void myMethod(params object[] something) as in:
public static void Main()
{
UnknownArgumentsMethod1(1, 2, 3, "foo");
}
public static void UnknownArgumentsMethod1(params object[] list)
{
UnknownArgumentsMethod2(list);
}
public static void UnknownArgumentsMethod2(params object[] list)
{
foreach (object o in list)
{
if (o.GetType() == typeof(int))
{
Console.WriteLine("This is an integer: " + (int)o);
}
else if (o.GetType() == typeof(string))
{
Console.WriteLine("This is a string: " + (string)o);
}
}
}
The obvious answer would be to have inheritance.
In your case (even though the names of the classes suggest otherwise) the way to do it is by inheriting the ChildClass in the BaseClass and that way you would have the methods from the ChildClass exposed through the BaseClass.
ex:
class MyBaseClass: MyChildClass
{
}
If the classes are not related and you just want to have an instance of MyChildClass in MyBaseClass but only expose a certain set of methods but by not making the others private what you could do is expose the MyChildClass instance through an interface that only exposes the necessary fields like so:
public class BaseClass
{
public IChildClass ChildClassInstance = new ChildClass();
}
public class ChildClass : IChildClass
{
public void myMethod(int i)
{ /* do something with i */ }
public void myMethod(int a, string b)
{ /* get i from a and b and call: */ myMethod(i); }
public void myMethod(string c, string d)
{ /* get i from c and d and call: */ myMethod(i); }
}
public interface IChildClass
{
void myMethod(int i);
void myMethod(int a, string b);
}
and then you could access only the methods that you allow to be exposed through an instance of the base class:
BaseClass test = new BaseClass();
test.ChildClassInstance.myMethod(1);
test.ChildClassInstance.myMethod(1,"test");
I have an interesting problem. I need to wrap static classes dynamically. I.e. return a non-static instance to my callers. e.g.:
public object CreateInstance(string className) {
Type t = assembly.GetType(className);
if (IsStatic(t)) {
return CreateStaticWrapper(t);
} else {
return Activator.CreateInstance(t);
}
}
So what I need is pointers as to how to implement CreateStaticWrapper.
Note: I cannot use Dynamic objects unfortunately.
So what are my options? I'm not that keen on learning IL generation? If IL generation (Reflection.Emit, or is there other ways now?) is the way to go does anyone have pointers there?
Edit: It's important to note that I can return a Dictionary of Delegates. So I could use Delegate.CreateDelegate for this but I can't seem to work out how to handle overloaded methods and Generic methods.
Edit2: Another option would be to inject an empty constructor into the type using Emit, again any pointers? Is this even possible on a type marked as static? Does the static keyword make it into the IL?
Edit3: For a bit of context, I'm passing this to a javascript environment see: my project. So I would like to be able to (in JavaScript):
var fileHelper = .create('System.IO.File');
if (fileHelper.Exists(fileName)) { fileHelper.Delete(fileName); }
Thanks All.
Try creating a wrapper class which inherits from System.Dynamic.DynamicObject. In the wrapper class, use reflection to call the methods of the static class.
You need something like this:
public class StaticWrapper<T> : System.Dynamic.DynamicObject
{
private static readonly Type t = typeof(T);
public static int MyProperty { get; set; }
public override bool TryInvokeMember(System.Dynamic.InvokeMemberBinder binder, object[] args, out object result)
{
try
{
result = t.InvokeMember(binder.Name, BindingFlags.Static | BindingFlags.Public, null, null, args);
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TryGetMember(System.Dynamic.GetMemberBinder binder, out object result)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
result = p.GetValue(null, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) result = f.GetValue(null);
else { result = null; return false; }
}
return true;
}
catch
{
result = null;
return false;
}
}
public override bool TrySetMember(System.Dynamic.SetMemberBinder binder, object value)
{
try
{
var p = t.GetProperty(binder.Name);
if (p != null)
p.SetValue(null, value, null);
else
{
var f = t.GetField(binder.Name);
if (f != null) f.SetValue(null, value);
else return false;
}
return true;
}
catch (SystemException)
{
return false;
}
}
}
Hope it works.
I'd say go for IL generation. Creating a proxy is a pretty simple scenario. I actually wrote a blog post about it: einarwh.posterous.com/patching-polymorphic-pain-at-runtime. The scenario is different, but the solution almost identical.
You can basically do exactly as in the blog post, except you don't need to load the 'this' reference onto the stack (since you're doing static method calls).
Ok, well the solution I've come up with is as follows and was found reading through and studying Einar's blog post which he posted as a comment above. Thanks Einar.
But I thought I'd post my full code solution here in case it may help someone in the future:
using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
namespace js.net.jish.Command
{
public class StaticTypeWrapper
{
private readonly Type staticType;
public StaticTypeWrapper(Type staticType)
{
this.staticType = staticType;
}
public object CreateWrapper()
{
string ns = staticType.Assembly.FullName;
ModuleBuilder moduleBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName(ns), AssemblyBuilderAccess.Run).DefineDynamicModule(ns);
TypeBuilder wrapperBuilder = moduleBuilder.DefineType(staticType.FullName, TypeAttributes.Public, null, new Type[0]);
foreach (MethodInfo method in staticType.GetMethods().Where(mi => !mi.Name.Equals("GetType")))
{
CreateProxyMethod(wrapperBuilder, method);
}
Type wrapperType = wrapperBuilder.CreateType();
object instance = Activator.CreateInstance(wrapperType);
return instance;
}
private void CreateProxyMethod(TypeBuilder wrapperBuilder, MethodInfo method)
{
var parameters = method.GetParameters();
var methodBuilder = wrapperBuilder.DefineMethod(method.Name, MethodAttributes.Public | MethodAttributes.Virtual, method.ReturnType, parameters.Select(p => p.ParameterType).ToArray());
var gen = methodBuilder.GetILGenerator();
for (int i = 1; i < parameters.Length + 1; i++)
{
gen.Emit(OpCodes.Ldarg, i);
}
gen.Emit(OpCodes.Call, method);
gen.Emit(OpCodes.Ret);
}
}
}
So, say that we play around with the "Delegate.CreateDelegate" way. And let's see if we can get more details about your other issues after that... Let's start with:
public static object Generate(Type t)
{
if(IsStatic(t))
{
var dictionary = new Dictionary<string, Delegate>();
foreach (var methodInfo in t.GetMethods())
{
var d = Delegate.CreateDelegate(t, methodInfo);
dictionary[methodInfo.Name] = d;
}
return dictionary;
}
return Activator.CreateInstance(t);
}
Static classes are 'sealed' and can thus not be inherited. So I don't see what you mean by 'overloaded'. For generic methods, we need to invoke the methodInfo.MakeGenericMethod(...) before adding it to our dictionary. But then you would need to know the type beforehand, which I guess you don't... Alternatively, you can do something like:
...
if (methodInfo.IsGenericMethod)
{
d = new Func<MethodInfo, Type[], Delegate>(
(method, types) =>
Delegate.CreateDelegate(
method.DeclaringType, method.MakeGenericMethod(types)));
}
dictionary[methodInfo.Name] = d;
...
That would give you a delegate that would take a type array (the generic type parameters), and produce a working delegate from that.
In C# is there a technique using reflection to determine if a method has been added to a class as an extension method?
Given an extension method such as the one shown below is it possible to determine that Reverse() has been added to the string class?
public static class StringExtensions
{
public static string Reverse(this string value)
{
char[] cArray = value.ToCharArray();
Array.Reverse(cArray);
return new string(cArray);
}
}
We're looking for a mechanism to determine in unit testing that the extension method was appropriately added by the developer. One reason to attempt this is that it is possible that a similar method would be added to the actual class by the developer and, if it was, the compiler will pick that method up.
You have to look in all the assemblies where the extension method may be defined.
Look for classes decorated with ExtensionAttribute, and then methods within that class which are also decorated with ExtensionAttribute. Then check the type of the first parameter to see if it matches the type you're interested in.
Here's some complete code. It could be more rigorous (it's not checking that the type isn't nested, or that there is at least one parameter) but it should give you a helping hand.
using System;
using System.Runtime.CompilerServices;
using System.Reflection;
using System.Linq;
using System.Collections.Generic;
public static class FirstExtensions
{
public static void Foo(this string x) { }
public static void Bar(string x) { } // Not an ext. method
public static void Baz(this int x) { } // Not on string
}
public static class SecondExtensions
{
public static void Quux(this string x) { }
}
public class Test
{
static void Main()
{
Assembly thisAssembly = typeof(Test).Assembly;
foreach (MethodInfo method in GetExtensionMethods(thisAssembly, typeof(string)))
{
Console.WriteLine(method);
}
}
static IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly, Type extendedType)
{
var isGenericTypeDefinition = extendedType.IsGenericType && extendedType.IsTypeDefinition;
var query = from type in assembly.GetTypes()
where type.IsSealed && !type.IsGenericType && !type.IsNested
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(ExtensionAttribute), false)
where isGenericTypeDefinition
? method.GetParameters()[0].ParameterType.IsGenericType && method.GetParameters()[0].ParameterType.GetGenericTypeDefinition() == extendedType
: method.GetParameters()[0].ParameterType == extendedType
select method;
return query;
}
}
Based on John Skeet's answer I've created my own extension to the System.Type-type.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
namespace System
{
public static class TypeExtension
{
/// <summary>
/// This Methode extends the System.Type-type to get all extended methods. It searches hereby in all assemblies which are known by the current AppDomain.
/// </summary>
/// <remarks>
/// Insired by Jon Skeet from his answer on http://stackoverflow.com/questions/299515/c-sharp-reflection-to-identify-extension-methods
/// </remarks>
/// <returns>returns MethodInfo[] with the extended Method</returns>
public static MethodInfo[] GetExtensionMethods(this Type t)
{
List<Type> AssTypes = new List<Type>();
foreach (Assembly item in AppDomain.CurrentDomain.GetAssemblies())
{
AssTypes.AddRange(item.GetTypes());
}
var query = from type in AssTypes
where type.IsSealed && !type.IsGenericType && !type.IsNested
from method in type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)
where method.IsDefined(typeof(ExtensionAttribute), false)
where method.GetParameters()[0].ParameterType == t
select method;
return query.ToArray<MethodInfo>();
}
/// <summary>
/// Extends the System.Type-type to search for a given extended MethodeName.
/// </summary>
/// <param name="MethodeName">Name of the Methode</param>
/// <returns>the found Methode or null</returns>
public static MethodInfo GetExtensionMethod(this Type t, string MethodeName)
{
var mi = from methode in t.GetExtensionMethods()
where methode.Name == MethodeName
select methode;
if (mi.Count<MethodInfo>() <= 0)
return null;
else
return mi.First<MethodInfo>();
}
}
}
It get's all assemblies from the current AppDomain and searches for extended methods.
Usage:
Type t = typeof(Type);
MethodInfo[] extendedMethods = t.GetExtensionMethods();
MethodInfo extendedMethodInfo = t.GetExtensionMethod("GetExtensionMethods");
The next step would be to extend System.Type with methods, which returns all Methods (also the "normal" ones with the extended ones)
This will return a list of all extension methods defined in a certain type, including the generic ones:
public static IEnumerable<KeyValuePair<Type, MethodInfo>> GetExtensionMethodsDefinedInType(this Type t)
{
if (!t.IsSealed || t.IsGenericType || t.IsNested)
return Enumerable.Empty<KeyValuePair<Type, MethodInfo>>();
var methods = t.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Where(m => m.IsDefined(typeof(ExtensionAttribute), false));
List<KeyValuePair<Type, MethodInfo>> pairs = new List<KeyValuePair<Type, MethodInfo>>();
foreach (var m in methods)
{
var parameters = m.GetParameters();
if (parameters.Length > 0)
{
if (parameters[0].ParameterType.IsGenericParameter)
{
if (m.ContainsGenericParameters)
{
var genericParameters = m.GetGenericArguments();
Type genericParam = genericParameters[parameters[0].ParameterType.GenericParameterPosition];
foreach (var constraint in genericParam.GetGenericParameterConstraints())
pairs.Add(new KeyValuePair<Type, MethodInfo>(parameters[0].ParameterType, m));
}
}
else
pairs.Add(new KeyValuePair<Type, MethodInfo>(parameters[0].ParameterType, m));
}
}
return pairs;
}
There's only one problem with this: The Type returned is not the same you'd expect with typeof(..), because it's a generic parameter type. In order to find all the extension methods for a given type you'll have to compare the GUID of all the base types and interfaces of the Type like:
public List<MethodInfo> GetExtensionMethodsOf(Type t)
{
List<MethodInfo> methods = new List<MethodInfo>();
Type cur = t;
while (cur != null)
{
TypeInfo tInfo;
if (typeInfo.TryGetValue(cur.GUID, out tInfo))
methods.AddRange(tInfo.ExtensionMethods);
foreach (var iface in cur.GetInterfaces())
{
if (typeInfo.TryGetValue(iface.GUID, out tInfo))
methods.AddRange(tInfo.ExtensionMethods);
}
cur = cur.BaseType;
}
return methods;
}
To be complete:
I keep a dictionary of type info objects, that I build when iterating all the types of all assemblies:
private Dictionary<Guid, TypeInfo> typeInfo = new Dictionary<Guid, TypeInfo>();
where the TypeInfo is defined as:
public class TypeInfo
{
public TypeInfo()
{
ExtensionMethods = new List<MethodInfo>();
}
public List<ConstructorInfo> Constructors { get; set; }
public List<FieldInfo> Fields { get; set; }
public List<PropertyInfo> Properties { get; set; }
public List<MethodInfo> Methods { get; set; }
public List<MethodInfo> ExtensionMethods { get; set; }
}
To clarify a point Jon glossed over... "Adding" an extension method to a class does not change the class in any way. It's just a little bit of spinning performed by the C# compiler.
So, using your example, you may write
string rev = myStr.Reverse();
but the MSIL written to the assembly will be exactly as if you had written it:
string rev = StringExtensions.Reverse(myStr);
The compiler is merely letting you fool yourself into thinking you are calling an method of String.
One reason to attempt this is that it is possible that a similar method would be added to the actual class by the developer and, if it was, the compiler will pick that method up.
Suppose an extension method void Foo(this Customer someCustomer) is defined.
Suppose, also, that Customer is modified and the method void Foo() is added.
Then, the new method on Customer will cover/hide the extension method.
The only way to call the old Foo method at that point is:
CustomerExtension.Foo(myCustomer);
void Main()
{
var test = new Test();
var testWithMethod = new TestWithExtensionMethod();
Tools.IsExtensionMethodCall(() => test.Method()).Dump();
Tools.IsExtensionMethodCall(() => testWithMethod.Method()).Dump();
}
public class Test
{
public void Method() { }
}
public class TestWithExtensionMethod
{
}
public static class Extensions
{
public static void Method(this TestWithExtensionMethod test) { }
}
public static class Tools
{
public static MethodInfo GetCalledMethodInfo(Expression<Action> expr)
{
var methodCall = expr.Body as MethodCallExpression;
return methodCall.Method;
}
public static bool IsExtensionMethodCall(Expression<Action> expr)
{
var methodInfo = GetCalledMethodInfo(expr);
return methodInfo.IsStatic;
}
}
Outputs:
False
True
This is the solution using LINQ method syntax rather than query syntax based on #Jon Skeet's answer.
public static IEnumerable<MethodInfo> GetExtensionMethods(Assembly assembly, Type extendedType)
{
var methods = assembly.GetTypes()
.Where(type => type.IsSealed && !type.IsGenericType && !type.IsNested)
.SelectMany(type => type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic))
.Where(method => method.IsDefined(typeof(ExtensionAttribute), false) &&
method.GetParameters()[0].ParameterType == extendedType);
return methods;
}