I'm porting over some old code from AS3 (via Haxe) to C#.
Parts of the code are transpiled, others I have manually rewritten in C#. One of these parts is the event dispatching.
I have event listeners registering to an event dispatcher, all listeners have a signature like this:
public void handleSomething(Event e)
// they may also use a subclass of Event as a parameter
public void handleAnother(MouseEvent e)
The events keep a small amount of data and a type:
public class Event {
public const string ENTER_FRAME = "enter_frame";
public const string RESIZE = "resize";
public const string CHANGE = "change";
readonly string type;
public Event(string type) {
this.type = type;
}
}
I keep a list keyed on the particular event type (a string, due to legacy reasons), once an event is dispatched I find the appropriate handlers keyed with that string and call the them with the event data.
I am currently using reflection to do this, but it is proving to be prohibitively slow. I have found several threads that share this problem.
My particular issue is that the method signature varies, if it was always an Event as a parameter I could use the solutions provided, but alas.
I'd be fine with trading some memory/time at setup to get subsequent calls to be faster. I can get a reference to the method and work out what type it expects, but I'm unsure how to store and call this later?
You can create and compile LINQ expression for each handler method and cache it for future use.
public class CompiledDelegate
{
// Assume that there is one one method per handler class type, add method name to dictionary key if necessary
private static Dictionary<Type, CompiledDelegate> _Cache = new Dictionary<Type, CompiledDelegate>();
public static CompiledDelegate Get(Type handlerType, string methodName)
{
CompiledDelegate result;
if (!_Cache.TryGetValue(handlerType, out result))
{
var method = handlerType.GetMethod(methodName);
// determine type of single method parameter
var paramType = method.GetParameters().Single().ParameterType;
// create expression tree (object h, object p) => ((handlerType)h).MethodName((paramType)p)
var exprHandler = Expression.Parameter(typeof(object), "h");
var exprParam = Expression.Parameter(typeof(object), "p");
var lambda = Expression.Lambda(
Expression.Call(
Expression.TypeAs(exprHandler, handlerType), // instance, cast object to handlerType
method, // method
Expression.TypeAs(exprParam, paramType) // parameter, cast object to paramType
),
exprHandler, exprParam // lamda params
);
result = new CompiledDelegate()
{
Method = method,
// compile expression
Compiled = (Action<object, object>)lambda.Compile()
};
_Cache.Add(handlerType, result);
}
return result;
}
public MethodInfo Method { get; private set; }
public Action<object, object> Compiled { get; set; }
}
Once you have hander instance, you can call its method via compiled delegate:
CompiledDelegate.Get(handler.GetType(), "handlerSomething").Compiled(handler, mouseEvent)
You can pre-generate CompiledDelegate for each of handlers and add to the dispatch table together with handlers themselves.
Calling method via compiled delegate (once it's compiled of course) is approximately 10 times faster then calling same method via reflection.
Related
If I have an expression in the form of Expression<Func<Delegate>> is it possible to determine the derived type of the object used to pass in the delegate? Does the expression even contain this information, or is it exclusively representative of the delegate.
A code example should make things clearer.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
namespace Sandbox {
public interface IContract {
void Method();
}
public class Concrete : IContract {
public void Method() { }
}
public class Test {
private IContract contract = new Concrete();
private Concrete concrete = new Concrete();
public static string GetFullMethodName(Expression<Func<Action>> expression) {
var unaryExpression = (UnaryExpression)expression.Body;
var methodCallExpression = (MethodCallExpression)unaryExpression.Operand;
var methodInfoExpression = (ConstantExpression)methodCallExpression.Arguments.Last();
var methodInfo = (MemberInfo)methodInfoExpression.Value;
var type = methodInfo.DeclaringType;
var name = methodInfo.Name;
return String.Format("{0}.{1}", type, name);
}
public Test() {
var strConcrete = GetFullMethodName(() => concrete.Method); // Sandbox.Concrete.Method
var strContract = GetFullMethodName(() => contract.Method); // Sandbox.IContract.Method
}
}
}
Is it possible to make () => contract.Method produce
Sandbox.Concrete.Method
Instead of
Sandbox.IContract.Method
Can the expression be altered to support this, or would I be forced to pass an instance of the object as a separate parameter in order to determine it's type?
No, that isn't possible.
The expression tree is built based on compile-time information, and at compile-time, the method being invoked is the virtual IContract.Method. The fact that at runtime, the Concrete.Method is actually invoked is irrelevant - that's handled in the virtual dispatch mechanism and the compiler finished its job long before any of this is decided.
The best you can do is try to emulate virtual dispatch yourself. For example, you could try enumerating the interface implementation on the this instance at runtime, and if you do find a method that matches the interface, you'd return that. However, this is certainly tricky - you need to be able to perfectly emulate the actual virtual dispatch.
Another tricky point is that the way you're trying to get the value is already broken. For example, in my environment, the methodInfoExpression is not a ConstantExpression - it's a field on a closure type. Your "parsing" is very fragile.
That said, it's also kind of unnecessary and overcomplicated - you're trying to receive an expression that returns an action and "steal" the value of the action out of the expression. There's already a simple way of doing that - pass that argument directly. No need to hide it in an expression tree:
public static string GetFullMethodName(Action action)
{
return string.Format("{0}.{1}", action.Method.DeclaringType.Name, action.Method.Name);
}
var strConcrete = GetFullMethodName(concrete.Method).Dump(); // Sandbox.Concrete.Method
var strContract = GetFullMethodName(contract.Method).Dump(); // Sandbox.Concrete.Method
You don't need expressions for things that basic reflection already gives you :)
There is a third-party component library like this:
public static class GenericExcuteTestClassExtension
{
public static void Excute<T>(this GenericExcuteTestClass clazz,
string parameter, Action<ReturnClass<T>> callback)
{
ReturnClass<T> rClazz = new ReturnClass<T>(parameter);
rClazz.Property5 = typeof(T).ToString();
callback.Invoke(rClazz);
}
public static void Excute<T>(this GenericExcuteTestClass clazz,
string parameter, Action<ReturnClass> callback)
{
ReturnClass rClazz = new ReturnClass(parameter);
rClazz.Property5 = typeof(T).ToString();
callback.Invoke(rClazz);
}
}
I want to reflect to invoke the methodExcute<T>(this GenericExcuteTestClass clazz, string parameter, Action<ReturnClass<T>> callback).
I use thetypeof(GenericExcuteTestClassExtension).GetMethod("Excute", new Type[] { typeof(GenericExcuteTestClass), typeof(string), typeof(Action<ReturnClass<>>)}), but the compiler get the error "Type expected". How can I get type of (Action<ReturnClass<>>), Action<> can compliled, but it's not my expected.
I want to pass the a custom action<ReturnClass<>> like (result)=>{....} to the method, how can I do it?
Please help ,thanks.
Why I use reflect to execute this ?
Because this method must execute in aop intercept
this real situation is like this:
I want to use restsharp in my app, and I write an interface like
[RestfulService(Constants.BASE_URL + "/login")]
public interface UserService
{
[Request("/login")]
void Login([Paramter] string name, [Paramter] string password, Action<T> callBack);
}
and Intercept the interface to get the parameter to execute restsharp ExecuteAsync<T>(this IRestClient client, IRestRequest request, Action<IRestResponse<T>> callback) to get data.
So I need to pass the T in UserService to ExecuteAsync<T> in Intercept method public void Intercept(IInvocation invocation) of castle.windsor, in this method body, we only can get GenericType's Type cannnot get T, so if I directly call ExecuteAsync, I cannot pass the GenericType T to this method. I must use like this:...GetMethod("...").MakeGenericType(new Type[]{piLast.ParameterType.GenericTypeArguments})
The whole problem comes from the fact, that nested generic types are not well handled by the reflection system in .NET.
The simplest solution in your case is to filter the methods yourself. A quick&dirty snippet:
MethodInfo method = null;
foreach (var m in typeof(GenericExcuteTestClassExtension)
.GetMethods(BindingFlags.Public | BindingFlags.Static))
{
var parameters = m.GetParameters();
if (!parameters.Any())
continue;
var lastParameterType = parameters.Last().ParameterType;
var genericArgument = lastParameterType
.GetGenericArguments()
.SingleOrDefault();
// you can/should add more checks, using the Name for example
if (genericArgument != null && genericArgument.IsGenericType)
{
method = m;
break;
}
}
You should probably make an utility method from this. A general approach allowing to search for any method with nested generics can be found here. There is also another possibility using Expressions here.
I've copied the code from here: https://whathecode.wordpress.com/2012/03/26/null-checks-for-event-handlers-an-aspect-solution/
But I can't seem to get it to work when the event is within a generically typed class. I have a class defined as:
Public Class MultiKeyDictionary<TFirstKey, TSecondKey, TValue>
and the following events:
public delegate void EventDelegate(TValue value);
public delegate void ReplacedEventDelegate(TValue oldValue, TValue newValue);
public event EventDelegate Added;
public event EventDelegate Removed;
public event ReplacedEventDelegate Replaced;
But the initialisation code exceptions complaining that the type's ContainsGenericParameters is set to true (or something similar to that).
I've changed the code in that link in the RuntimeInitialize method to this:
public override void RuntimeInitialize(EventInfo eventInfo) {
base.RuntimeInitialize(eventInfo);
Type eventType;
MethodInfo delegateInfo = eventInfo.EventHandlerType.MethodInfoFromDelegateType();
ParameterExpression[] parameters = delegateInfo.GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray();
if(eventInfo.EventHandlerType.ContainsGenericParameters) {
var genericDelegate = eventInfo.EventHandlerType.GetGenericTypeDefinition();
var genericParams = genericDelegate.GetGenericArguments();
eventType = genericDelegate.MakeGenericType(genericParams);
} else {
eventType = eventInfo.EventHandlerType;
}
Delegate emptyDelegate = Expression.Lambda(eventType, Expression.Empty(), "EmptyDelegate", true, parameters).Compile();
this.addEmptyEventHandler = instance => eventInfo.AddEventHandler(instance, emptyDelegate);
}
But all I get now is an ArgumentException: ParameterExpression of type 'TValue' cannot be used for delegate parameter of type 'TValue' on the line creating emptyDelegate.
As I replied earlier on my blog, the main problem here is when RuntimeInitialize() is called PostSharp doesn't know yet with which generic arguments the class will be initialized. However when OnConstructorEntry() is called we do have this information. For more information about how PostSharp aspects work, be sure to read the documentation on Aspect lifetimes.
In the existing code, when the aspect is created at runtime for the class (the RuntimeInitialize() method) I simply ignored the fact that the class could be generic. This was on oversight on my part. You can't compile 'generic' types using Expression.Lambda, hence it is impossible to compile a common event handler which can be used by all different instantiations of the generic type.
You need to compile this empty event handler at run time for each different instantiation of the generic type separately. This can be done in OnConstructorEntry where you can receive the instance type from the MethodExecutionArgs parameter passed by PostSharp.
In order to know which event you need to add a handler to, you need to store EventInfo in your aspect at runtime initialization.
[NonSerialized]
EventInfo _event;
You know which event the aspect applies to by comparing names. What follows is currently working code from OnConstructorEntry().
Type runtimeType = args.Instance.GetType();
EventInfo runtimeEvent =
runtimeType.GetEvents().Where( e => e.Name == _event.Name ).First();
MethodInfo delegateInfo =
DelegateHelper.MethodInfoFromDelegateType( runtimeEvent.EventHandlerType );
ParameterExpression[] parameters = delegateInfo
.GetParameters()
.Select( p => Expression.Parameter( p.ParameterType ) )
.ToArray();
Delegate emptyDelegate = Expression.Lambda(
runtimeEvent.EventHandlerType, Expression.Empty(),
"EmptyDelegate", true, parameters ).Compile();
// Add the empty handler to the instance.
MethodInfo addMethod = runtimeEvent.GetAddMethod( true );
if ( addMethod.IsPublic )
{
runtimeEvent.AddEventHandler( args.Instance, emptyDelegate );
}
else
{
addMethod.Invoke( args.Instance, new object[] { emptyDelegate } );
}
This still leaves open one problem. We do not want to do all this reflection every time the type is constructed! Therefore ideally you should cache the method which adds the empty handler as previously in RuntimeInitialize(). Since the aspect code is 'shared' by all instantiations of the generic type (they use the same scope), you should cache for each instance type separately. E.g. using a Dictionary<Type, Action<object>>, where Type refers to the instance type and Action<object> is the method which can add the empty event handler to the instance.
This is exactly the implementation I now use in my library, of which you can find the updated version on github. As you will see I use a CachedDictionary class, which handles most of the caching logic already for you since it is such a common scenario. The previously failing unit test now succeeds.
I have been testing out using delegates instead of reflection for some object sorting and it was working good for string properties, but if I try an Int (or DateTime) it fails and throws
Error binding to target method.
class Program
{
static void Main(string[] args)
{
var sample = new SampleClass() { Num = 13, Text = "Sample" };
Console.WriteLine(ReadProp(sample,"Text")); //Works
Console.WriteLine(ReadProp(sample, "classProp")); //Works
Console.WriteLine(ReadProp(sample, "Num")); //Throws 'Error binding to target method.'
}
//Use a Delegate to improve speed of accessing property instead of reflection
static object ReadProp(SampleClass obj, string propName)
{
var method = obj.GetType().GetProperty(propName).GetGetMethod();
var getForProp = (Func<SampleClass, object>)Delegate.CreateDelegate(typeof(Func<SampleClass, object>), null, method);
return getForProp(obj);
}
}
//A sample class for illustration purposes
class SampleClass
{
public string Text { get; set; }
public int Num { get; set; }
public SampleClass classProp { get; set; }
}
My question is: Why does it work for strings or other classes but not for Int or DateTime?
I can see that if I change my Func<SampleClass, object> to Func<SampleClass, int> it will then work for my Int but I expected object would work for both.
Why does it work for strings or other classes but not for Int or DateTime?
Because a method which returns an int isn't a method which returns an object reference. There has to be a boxing conversion - so something's got to do that, and Delegate.CreateDelegate is trying to provide a delegate which just invokes the delegate and returns the result, with no value conversion involved.
It's slightly painful to do, but basically I suspect you should either be building a Func with an appropriate return value and using that directly or you should go via a wrapper delegate which calls the "real" delegate and boxes the result.
(Note that in your sample code, you're creating the delegate each time, which is going to be no faster than reflection. Hopefully your real code is more sensible :)
If you look at this code from protobuf-csharp-port you'll see I've got a method to do exactly this - a lambda expression calls the strongly-typed delegate, and then uses the implicit conversion to object (boxing where necessary) to provide the value. You should be able to use something very similar. However, if you're sorting do you really want a Func<T, object>? If you use a strongly-typed delegate instead, you may be able to avoid all this boxing.
The topic of how C# virtual and override mechanism works internally has been discussed to death amongst the programmers... but after half an hour on google, I cannot find an answer to the following question (see below):
Using a simple code:
public class BaseClass
{
public virtual SayNo() { return "NO!!!"; }
}
public class SecondClass: BaseClass
{
public override SayNo() { return "No."; }
}
public class ThirdClass: SecondClass
{
public override SayNo() { return "No..."; }
}
class Program
{
static void Main()
{
ThirdClass thirdclass = new ThirdClass();
string a = thirdclass.SayNo(); // this would return "No..."
// Question:
// Is there a way, not using the "new" keyword and/or the "hide"
// mechansim (i.e. not modifying the 3 classes above), can we somehow return
// a string from the SecondClass or even the BaseClass only using the
// variable "third"?
// I know the lines below won't get me to "NO!!!"
BaseClass bc = (BaseClass)thirdclass;
string b = bc.SayNo(); // this gives me "No..." but how to I get to "NO!!!"?
}
}
I think I can't get to the methods of base class or the intermediate derived class simply using the most derived instance (without modifying the method signatures of the 3 classes). But I would like to confirm and cement my understanding...
Thanks.
C# can't do this but it is actually possible in IL using call instead of callvirt. You can thus work around C#'s limitation by using Reflection.Emit in combination with a DynamicMethod.
Here's a very simple example to illustrate how this works. If you really intend to use this, wrap it inside a nice function strive to make it work with different delegate types.
delegate string SayNoDelegate(BaseClass instance);
static void Main() {
BaseClass target = new SecondClass();
var method_args = new Type[] { typeof(BaseClass) };
var pull = new DynamicMethod("pull", typeof(string), method_args);
var method = typeof(BaseClass).GetMethod("SayNo", new Type[] {});
var ilgen = pull.GetILGenerator();
ilgen.Emit(OpCodes.Ldarg_0);
ilgen.EmitCall(OpCodes.Call, method, null);
ilgen.Emit(OpCodes.Ret);
var call = (SayNoDelegate)pull.CreateDelegate(typeof(SayNoDelegate));
Console.WriteLine("callvirt, in C#: {0}", target.SayNo());
Console.WriteLine("call, in IL: {0}", call(target));
}
Prints:
callvirt, in C#: No.
call, in IL: NO!!!
Without modification to your sample and discounting reflection, no there is no way. The intent of the virtual system is to enforce calling the derived most no matter what and the CLR is good at its job.
There are a couple of ways you can work around this though.
Option 1: You could add the following method to ThirdClass
public void SayNoBase() {
base.SayNo();
}
This would force the invocation of SecondClass.SayNo
Option 2: The main problem here is that you want to invoke a virtual method non-virtually. C# only provides one way of doing this via the base modifier. This makes it impossible to call a method within your own class in a non-virtual fashion. You can fix this by factoring it out into a second method and proxying.
public overrides void SayNo() {
SayNoHelper();
}
public void SayNoHelper() {
Console.WriteLine("No");
}
Sure...
BaseClass bc = new BaseClass();
string b = bc.SayNo();
"Virtual" means that the implementation which will be executed is based on the ACTUAL type of the underlying object, not the type of the variable it is stuffed in... So if the actual object is a ThirdClass, that's the implementation you will get, no matter what you cast it to. If you want the behavior you describe above, don't make the methods virtual...
If you're wondering "what's the point?" it's for 'polymorphism'; so that you can declare a collection, or a method parameter, as some base type, and include/ pass it a mix of derived types, and yet when, within the code, even though each object is assigned to a ref variable declared as the base type, for each one, the actual implementation which will be executed for any virtual method call will be that implementation defined in the class definition for the ACTUAL tyoe of each object...
Using base in C# only works for the immediate base. You can't access a base-base member.
It looks someone else beat me to the punch with the answer about it being possible to do in IL.
However, I think the way I did the code gen has some advantages, so I'll post it anyways.
The thing I did differently is to use expression trees, which enable you to use the C# compiler to do overload resolution and generic argument substitution.
That stuff is complicated, and you don't want to have to replicate it your self if you can help it.
In your case, the code would work like this:
var del =
CreateNonVirtualCall<Program, BaseClass, Action<ThirdClass>>
(
x=>x.SayNo()
);
You would probably want to store the delegate in a readonly static field, so that you only have to compile it once.
You need to specify 3 generic arguments:
The owner type - This is the class that you would have invoked the code from if you were not using "CreateNonVirtualCall".
The base class - This is the class you want to make the non virtual call from
A delegate type. This should represent the signature of the method being called with an extra parameter for the "this" argument. It's possible to eliminate this, but it requires more work in the code gen method.
The method takes a single argument, a lambda representing the call. It has to be a call, and only a call. If you want to extend the code gen you can support more complex stuff.
For simplicicty, the lambda body is restricted to only being able to access lambda parameters, and can only pass them in directly to the function. You can remove this restriction if you extend the code gen in the method body to support all expression types. That would take some work though. You can do anything you want with the delegate that comes back, so the restriction isn't too big of a deal.
It's important to note that this code is not perfect. It could use a lot more validation, and it doesn't work with "ref" or "out" parameters because of expression tree limitations.
I did test it in sample cases with void methods, methods returning values, and generic methods, and it worked. I'm sure, however, you can find some edge cases that don't work.
In any case, here's the IL Gen Code:
public static TDelegate CreateNonVirtCall<TOwner, TBase, TDelegate>(Expression<TDelegate> call) where TDelegate : class
{
if (! typeof(Delegate).IsAssignableFrom(typeof(TDelegate)))
{
throw new InvalidOperationException("TDelegate must be a delegate type.");
}
var body = call.Body as MethodCallExpression;
if (body.NodeType != ExpressionType.Call || body == null)
{
throw new ArgumentException("Expected a call expression", "call");
}
foreach (var arg in body.Arguments)
{
if (arg.NodeType != ExpressionType.Parameter)
{
//to support non lambda parameter arguments, you need to add support for compiling all expression types.
throw new ArgumentException("Expected a constant or parameter argument", "call");
}
}
if (body.Object != null && body.Object.NodeType != ExpressionType.Parameter)
{
//to support a non constant base, you have to implement support for compiling all expression types.
throw new ArgumentException("Expected a constant base expression", "call");
}
var paramMap = new Dictionary<string, int>();
int index = 0;
foreach (var item in call.Parameters)
{
paramMap.Add(item.Name, index++);
}
Type[] parameterTypes;
parameterTypes = call.Parameters.Select(p => p.Type).ToArray();
var m =
new DynamicMethod
(
"$something_unique",
body.Type,
parameterTypes,
typeof(TOwner)
);
var builder = m.GetILGenerator();
var callTarget = body.Method;
if (body.Object != null)
{
var paramIndex = paramMap[((ParameterExpression)body.Object).Name];
builder.Emit(OpCodes.Ldarg, paramIndex);
}
foreach (var item in body.Arguments)
{
var param = (ParameterExpression)item;
builder.Emit(OpCodes.Ldarg, paramMap[param.Name]);
}
builder.EmitCall(OpCodes.Call, FindBaseMethod(typeof(TBase), callTarget), null);
if (body.Type != typeof(void))
{
builder.Emit(OpCodes.Ret);
}
var obj = (object) m.CreateDelegate(typeof (TDelegate));
return obj as TDelegate;
}
You can't get to the base methods of an override. No matter how you cast the object, the last override in the instance is always used.
If its backed with a field you could pull out the field using reflection.
Even if you pull off the methodinfo using reflection from typeof(BaseClass) you will still end up executing your overridden method