Can I use reflection with RealProxy instances? - c#

I'm quite sure I'm missing some constraint or caveat somewhere, but here's my situation. Assume I have a class that I want to have a proxy for, like the following:
public class MyList : MarshalByRefObject, IList<string>
{
private List<string> innerList;
public MyList(IEnumerable<string> stringList)
{
this.innerList = new List<string>(stringList);
}
// IList<string> implementation omitted for brevity.
// For the sake of this exercise, assume each method
// implementation merely passes through to the associated
// method on the innerList member variable.
}
I want to create a proxy for that class, so that I can intercept method calls and perform some processing on the underlying object. Here is my implementation:
public class MyListProxy : RealProxy
{
private MyList actualList;
private MyListProxy(Type typeToProxy, IEnumerable<string> stringList)
: base(typeToProxy)
{
this.actualList = new MyList(stringList);
}
public static object CreateProxy(IEnumerable<string> stringList)
{
MyListProxy listProxy = new MyListProxy(typeof(MyList), stringList);
object foo = listProxy.GetTransparentProxy();
return foo;
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage callMsg = msg as IMethodCallMessage;
MethodInfo proxiedMethod = callMsg.MethodBase as MethodInfo;
return new ReturnMessage(proxiedMethod.Invoke(actualList, callMsg.Args), null, 0, callMsg.LogicalCallContext, callMsg);
}
}
Finally, I have a class that consumes the proxied class, and I set the value of the MyList member via reflection.
public class ListConsumer
{
public MyList MyList { get; protected set; }
public ListConsumer()
{
object listProxy = MyListProxy.CreateProxy(new List<string>() { "foo", "bar", "baz", "qux" });
PropertyInfo myListPropInfo = this.GetType().GetProperty("MyList");
myListPropInfo.SetValue(this, listProxy);
}
}
Now, if I try to use reflection to access the proxied object, I run into problems. Here is an example:
class Program
{
static void Main(string[] args)
{
ListConsumer listConsumer = new ListConsumer();
// These calls merely illustrate that the property can be
// properly accessed and methods called through the created
// proxy without issue.
Console.WriteLine("List contains {0} items", listConsumer.MyList.Count);
Console.WriteLine("List contents:");
foreach(string stringValue in listConsumer.MyList)
{
Console.WriteLine(stringValue);
}
Type listType = listConsumer.MyList.GetType();
foreach (Type interfaceType in listType.GetInterfaces())
{
if (interfaceType.IsGenericType && interfaceType.GetGenericTypeDefinition() == typeof(ICollection<>))
{
// Attempting to get the value of the Count property via
// reflection throws an exception.
Console.WriteLine("Checking interface {0}", interfaceType.Name);
System.Reflection.PropertyInfo propInfo = interfaceType.GetProperty("Count");
int count = (int)propInfo.GetValue(listConsumer.MyList, null);
}
else
{
Console.WriteLine("Skipping interface {0}", interfaceType.Name);
}
}
Console.ReadLine();
}
}
Attempting to call GetValue on the Count property via reflection throws the following exception:
An exception of type 'System.Reflection.TargetException' occurred in
mscorlib.dll but was not handled in user code
Additional information: Object does not match target type.
When attempting to get the value of the Count property, apparently the framework is calling down into System.Runtime.InteropServices.WindowsRuntime.IVector to call the get_Size method. I'm not understanding how this call fails on the underlying object of the proxy (the actual list) to make this happen. If I'm not using a proxy of the object, getting the property value works fine via reflection. What am I doing wrong? Can I even do what I'm trying to accomplish?
Edit: A bug has been opened regarding this issue at the Microsoft Connect site.

I think this may be a bug in the .Net framework. Somehow the RuntimePropertyInfo.GetValue method is picking the wrong implementation for the ICollection<>.Count property, and it appears to have to do with WindowsRuntime projections. Perhaps the remoting code was redone when they put the WindowsRuntime interop in the framework.
I switched the framework to target .Net 2.0 since I thought if this was a bug, it shouldn't be in that framework. When converting, Visual Studio removed the "Prefer 32 bit" check on my console exe project (since this doesn't exist in 2.0). It runs without exception when this is not present.
In summary, it runs on .Net 2.0 in both 32 and 64 bit. It runs on .Net 4.x in 64 bit. The exception is thrown on .Net 4.x 32 bit only. This sure looks like a bug. If you can run it 64-bit, that would be a workaround.
Note that I've installed .Net 4.6, and this replaces much of the .Net framework v4.x. It could be this is where the problem is introduced; I can't test until I get a machine that doesn't have .Net 4.6.
Update: 2015-09-08
It also happens on a machine with only .Net 4.5.2 installed (no 4.6).
Update: 2015-09-07
Here's a smaller repro, using your same classes:
static void Main(string[] args)
{
var myList = MyListProxy.CreateProxy(new[] {"foo", "bar", "baz", "quxx"});
var listType = myList.GetType();
var interfaceType = listType.GetInterface("System.Collections.Generic.ICollection`1");
var propInfo = interfaceType.GetProperty("Count");
// TargetException thrown on 32-bit .Net 4.5.2+ installed
int count = (int)propInfo.GetValue(myList, null);
}
I've also tried the IsReadOnly property, but it appears to work (no exception).
As to the source of the bug, there are two layers of indirection around properties, one being the remoting, and the other being a mapping of metadata structures called MethodDefs with the actual runtime method, known internally as a MethodDesc. This mapping is specialized for properties (as well as events), where additional MethodDescs to support the property's get/set PropertyInfo instances are known as Associates. By calling PropertyInfo.GetValue we go through one of these Associate MethodDesc pointers to the underlying method implementation, and remoting does some pointer math to get the correct MethodDesc on the other side of the channel. The CLR code is very convoluted here, and I don't have enough experience of the in-memory layout of the MethodTable which holds these MethodDesc records which remoting uses (or the mapping it uses to get to the MethodTable?), but I'd say it's a fair guess that remoting is grabbing the wrong MethodDesc via some bad pointer math. That's why we see a similar but unrelated (as far as your program) MethodDesc - UInt32 get_Size of IVector<T> being invoked on the call:
System.Reflection.RuntimeMethodInfo.CheckConsistency(Object target)
System.Reflection.RuntimeMethodInfo.InvokeArgumentsCheck(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
System.Reflection.MethodBase.Invoke(Object obj, Object[] parameters)
ConsoleApplication1.MyListProxy.Invoke(IMessage msg) Program.cs: line: 60
System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
System.Runtime.InteropServices.WindowsRuntime.IVector`1.get_Size()
System.Runtime.InteropServices.WindowsRuntime.VectorToCollectionAdapter.Count[T]()

This is a pretty interesting CLR bug, some of its guts are showing in the mishap. You can tell from the stack trace that it is trying to call the VectorToCollectionAdapter's Count property.
This class is rather special, no instance of it ever gets created. It is part of the language projection that was added in .NET 4.5 that makes WinRT interface types look like .NET Framework types. It is pretty similar to the SZArrayHelper class, an adapter class that helps implement the illusion that non-generic arrays implement generic interface types like IList<T>.
The interface mapping at work here is for the WinRT IVector<T> interface. As noted in the MSDN article, that interface type is mapped to IList<T>. The internal VectorToListAdapter class takes care of the IList<T> members, VectorToCollectionAdapter tackles the ICollection<T> members.
Your code forces the CLR to find the implementation of ICollection<>.Count and that could either be a .NET class implementing it as normal or it could be a WinRT object that exposes it as IVector<>.Size. Clearly the proxy you created gives it a headache, it incorrectly decided for the WinRT version.
How it is supposed to figure out which is the correct choice is pretty murky. After all, your proxy could be a proxy for an actual WinRT object and then the choice it made would be correct. This could well be a structural problem. That it acts so randomly, the code does work in 64-bit mode, is not exactly inspiring. VectorToCollectionAdapter is very dangerous, note the JitHelpers.UnsafeCast calls, this bug is potentially exploitable.
Well, alert the authorities, file a bug report at connect.microsoft.com. Let me know if you don't want to take the time and I'll take care of it. A workaround is hard to come by, using the WinRT-centric TypeInfo class to do the reflection did not make any difference. Removing the jitter forcing so it runs in 64-bit mode is a band-aid but hardly a guarantee.

we are currently hacking around this problem with this brittle intervention (apologies for code):
public class ProxyBase : RealProxy
{
// ... stuff ...
public static T Cast<T>(object o)
{
return (T)o;
}
public static object Create(Type interfaceType, object coreInstance,
IEnforce enforce, string parentNamingSequence)
{
var x = new ProxyBase(interfaceType, coreInstance, enforce,
parentNamingSequence);
MethodInfo castMethod = typeof(ProxyBase).GetMethod(
"Cast").MakeGenericMethod(interfaceType);
return castMethod.Invoke(null, new object[] { x.GetTransparentProxy() });
}
public override IMessage Invoke(IMessage msg)
{
IMethodCallMessage methodCall = (IMethodCallMessage)msg;
var method = (MethodInfo)methodCall.MethodBase;
if(method.DeclaringType.IsGenericType
&& method.DeclaringType.GetGenericTypeDefinition().FullName.Contains(
"System.Runtime.InteropServices.WindowsRuntime"))
{
Dictionary<string, string> methodMap = new Dictionary<string, string>
{ // add problematic methods here
{ "Append", "Add" },
{ "GetAt", "get_Item" }
};
if(methodMap.ContainsKey(method.Name) == false)
{
throw new Exception("Unable to resolve '" + method.Name + "'.");
}
// thanks microsoft
string correctMethod = methodMap[method.Name];
method = m_baseInterface.GetInterfaces().Select(
i => i.GetMethod(correctMethod)).Where(
mi => mi != null).FirstOrDefault();
if(method == null)
{
throw new Exception("Unable to resolve '" + method.Name +
"' to '" + correctMethod + "'.");
}
}
try
{
if(m_coreInstance == null)
{
var errorMessage = Resource.CoreInstanceIsNull;
WriteLogs(errorMessage, TraceEventType.Error);
throw new NullReferenceException(errorMessage);
}
var args = methodCall.Args.Select(a =>
{
object o;
if(RemotingServices.IsTransparentProxy(a))
{
o = (RemotingServices.GetRealProxy(a)
as ProxyBase).m_coreInstance;
}
else
{
o = a;
}
if(method.Name == "get_Item")
{ // perform parameter conversions here
if(a.GetType() == typeof(UInt32))
{
return Convert.ToInt32(a);
}
return a;
}
return o;
}).ToArray();
// this is where it barfed
var result = method.Invoke(m_coreInstance, args);
// special handling for GetType()
if(method.Name == "GetType")
{
result = m_baseInterface;
}
else
{
// special handling for interface return types
if(method.ReturnType.IsInterface)
{
result = ProxyBase.Create(method.ReturnType, result, m_enforce, m_namingSequence);
}
}
return new ReturnMessage(result, args, args.Length, methodCall.LogicalCallContext, methodCall);
}
catch(Exception e)
{
WriteLogs("Exception: " + e, TraceEventType.Error);
if(e is TargetInvocationException && e.InnerException != null)
{
return new ReturnMessage(e.InnerException, msg as IMethodCallMessage);
}
return new ReturnMessage(e, msg as IMethodCallMessage);
}
}
// ... stuff ...
}
m_coreInstance here is the object instance that the proxy is wrapping.
m_baseInterface is the interface the object is to be used as.
this code intercepts the call(s) made in VectorToListAdapter and VectorToCollectionAdapter and converts it back into the original via that methodMap dictionary.
the part of the conditional:
method.DeclaringType.GetGenericTypeDefinition().FullName.Contains(
"System.Runtime.InteropServices.WindowsRuntime")
makes sure it only intercepts calls that come from stuff in the System.Runtime.InteropServices.WindowsRuntime namespace - ideally we would target the types directly but they are inaccessible - this should probably be changed to target specific class names in the namespace.
the parameters are then cast into the appropriate types and the method is invoked. the parameter conversions appear to be necessary as the incoming parameter types are based on the parameter types of the method calls from the objects in the System.Runtime.InteropServices.WindowsRuntime namespace, and not the parameters of the method calls to the original object types; i.e. the original types before the objects in the System.Runtime.InteropServices.WindowsRuntime namespace hijacked the mechanism.
for example, the WindowsRuntime stuff intercepts the original call to get_Item, and converts it into a call to the Indexer_Get method: http://referencesource.microsoft.com/#mscorlib/system/runtime/interopservices/windowsruntime/vectortolistadapter.cs,de8c78a8f98213a0,references. this method then calls the GetAt member with a different parameter type, which then calls GetAt on our object (again with a different parameter type) - this is the call we hijack in our Invoke() and convert it back into the original method call with the original parameter types.
it would be nice to be able to reflect over VectorToListAdapter and VectorToCollectionAdapter to extract all their methods and the nested calls they make, but these classes are unfortunately marked as internal.
this works for us here, but i'm sure its full of holes - it is a case of trial and error, running it to see what fails and then adding in the required dictionary entries/parameter conversions. we are continuing the search for a better solution.
HTH

Related

Can you pass generic delegate without the type parameter?

I have three projects
MVC Web application
Service application which is kind of two layers business/repository
Entity framework (all EF configuration lives here)
MVC references > service
Service references > EF
I have these three methods currently that do some work.
public bool StoreUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool RemoveUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool CommitUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
I call these three methods from my controller using these interfaces which delegate to the work methods above:
Boolean StoreUpload(UploadInformation information);
Boolean RemoveUpload(UploadInformation information);
Boolean CommitStoredDocuments(UploadInformation information);
Based on a condition from UploadTypes enumeration in a switch I call the correct work method. I do this because I don't want my mvc project to have access to the EF database types otherwise I know someone is going to start querying data from all over the application. I use these switch statements for all interfaced methods:
public bool StoreUpload(UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return RemoveUpload<AutoIncident>(information);
case UploadTypes.Incident:
return RemoveUpload<IncidentInjury>(information);
case UploadTypes.Inspection:
return RemoveUpload<Inspection>(information);
case UploadTypes.OtherIncident:
return RemoveUpload<OtherIncident>(information);
default:
return false;
}
}
public bool RemoveUpload(UploadInformation information) { ... }
public bool CommitStoredUpload(UploadInformation information) { ... }
This method might shed a little light on what the types parameters are being used for. I am updating tables in a generic way using EF.
private bool CommitStoredDocuments<T>(UploadInformation information) where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
...
}
It would be nice to be able to pass the work method which requires a type parameter as a delegate to the switch work method calls.
public bool DoSomeWork(delegateMethod, information) {
switch(information.Type) {
case UploadTypes.AutoInciden:
return delegateMethod<AutoIncident>(information);
...
}
}
Can this be done?
Also, I had trouble constructing a good title for this question so please comment if these is a better way to describe the challenge.
It cannot be done directly due to several reasons.
First of all, as you probably noticed, delegateMethod<FooBar>(information) simply does not compile. This is because in your example the delegateMethod is a local variable (method parameter actually, but still a variable), and you cannot apply "type arguments" <FooBar> to a variable - you can apply them only on an identifier that indicates a (generic) type or a (generic) method.
Second reason is more interesting. When you pass a method as a delegate, the delegate actually catches the whole method signature, including all parameter types.
void Blah<T>(UploadInformation information){ ... }
var one = new Action<int>(Blah); // -> Blah<int>
var two = new Action<float>(Blah); // -> Blah<float>
var thr = new Action<andsoon>(Blah); // -> Blah<andsoon>
MagicDoSomeWork(one, ...); // these all
MagicDoSomeWork(two, ...); // delegates are already bound
MagicDoSomeWork(thr, ...); // and remember their concrete T
You need to actually specify the type for the Action so a proper version of generic method will be picked from a general description called Blah. These delegates are bound to concrete versions of the method and will accept only that types. These delegates are 'closed' in terms of their type arguments. Using normal ways, the MagicDoSomeWork will simply have no way of altering the T which these delegates already have remembered.
That two things are a kind of show stoppers, since by normal code only, you cannot write things like
var nope1 = new Action(Blah); // ctor for Action NEEDS type parameter
since Action constructor simply requires a type parameter. And once you pass any, it will lock the Blah type arguments
Also you cannot use open delegates:
var nope1 = new Action<>(Blah); // can't use empty <> in this context :(
since new operator requires a full type to create an object.
However, with a bit of reflection voodoo, it is possible to analyze and build a generic type or a generic method dynamically.
// first, build the delegate in a normal way
// and pick anything as the type parameters
// we will later replace them
var delegateWithNoType = new Action<object>(Blah);
// delegate has captured the methodinfo,
// but uses a stub type parameter - it's useless to call it
// but it REMEMBERS the method!
// .... pass the delegate around
// later, elsewhere, determine the type you want to use
Type myRealArgument;
switch(..oversomething..)
{
default: throw new NotImplemented("Ooops");
case ...: myRealArgument = typeof(UploadTypes.AutoIncident); break;
...
}
// look at the delegate definition
var minfo = delegateWithNoType.Method;
var target = delegateWithNoType.Target; // probably NULL since you cross layers
var gdef = minfo.GetGenericDefinition();
var newinfo = gdef.MakeGenericMethod( myRealArgument );
// now you have a new MethodInfo object that is bound to Blah method
// using the 'real argument' type as first generic parameter
// By using the new methodinfo and original target, you could now build
// an updated delegate object and use it instead the original "untyped" one
// That would be a NEW delegate object. You can't modify the original one.
// ...but since you want to call the method, why don't use the methodinfo
UploadInformation upinfo = ... ;
newinfo.Invoke(target, new object[] { upinfo });
// -> will call Blah<UploadTypes.AutoInciden>(upinfo)
word of warning: this is a sketch to show you how the delegate.Method/Target and methodinfo and getgenericdefinition and makegenericmethod work. I wrote it from memory, never compiled, never ran. It can contain minor typos, overlooked things and invisible rainbow unicorns. I didn't noticed any. Probably because they were invisible.
You can do it like this
public bool Invoke(EntityType entityType, ActionType action, Object[] arguments)
{
var actionType = Enum.GetName(typeof(ActionType), action);
var type = GetType();
var method = type.GetMethods().Single(m => m.IsGenericMethod && m.Name == actionType);
switch (entityType)
{
case EntityType.IncidentInjury:
var genericMethod = method.MakeGenericMethod(typeof(IncidentInjury));
return (bool)genericMethod.Invoke(this, arguments);
default:
return false;
}
}
The enum will just be a list of methods that I want to invoke this way and I create a base class for my services so I don't have to pass the instance to the Invoke method.
Instead of using delegates, consider using an interface (or abstract class). This way, your methods can retain their generic nature.
For example, if you create an interface like:
interface IUploadAction
{
bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity;
}
Note that the T is not exposed in the type, it's only on the method. This is the key part.
Now you can implement this for your database methods:
class CommitStoredDocuments : IUploadAction
{
public bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
//...
}
}
Your switching/dispatching method can look like this:
public bool DoAction(IUploadAction action, UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return action.Perform<AutoIncident>(information);
case UploadTypes.Incident:
return action.Perform<IncidentInjury>(information);
case UploadTypes.Inspection:
return action.Perform<Inspection>(information);
case UploadTypes.OtherIncident:
return action.Perform<OtherIncident>(information);
default:
return false;
}
}
And then you can write something like:
IUploadAction storeUpload;
public bool StoreUpload(UploadInformation information) => DoAction(storeUpload, information);

MakeGenericMethod/MakeGenericType on Xamarin.iOS

I'm trying to figure out what the limitations really means when deploying for iOS from Xamarin.
http://developer.xamarin.com/guides/ios/advanced_topics/limitations/
I was under the impression that you have no JIT and thus any MakeGenericMethod or MakeGenericType would NOT work as that would require JIT compilation.
Also I understood that when running on the simulator, these restrictions does not apply since the simulator is not running in the full AOT (Ahead of Time) mode.
After setting up my Mac so that I could deploy to my phone, I would except the following test to fail when running on the actual device (iPhone).
[Test]
public void InvokeGenericMethod()
{
var method = typeof(SampleTests).GetMethod ("SomeGenericMethod");
var closedMethod = method.MakeGenericMethod (GetTypeArgument());
closedMethod.Invoke (null, new object[]{42});
}
public static void SomeGenericMethod<T>(T value)
{
}
private Type GetTypeArgument()
{
return typeof(int);
}
The thing is that completes successfully and I can't really understand why. Does not this code require JIT compilation?
In an effort to "make it break" , I also did a test with MakeGenericType.
[Test]
public void InvokeGenericType()
{
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}
public class SomeGenericClass<T>
{
public void Execute(T value)
{
}
}
How can this work when there is no JIT?
Am I missing something ?
In order to make the code fail go to iOS project options, tab "iOS Build" and change the "Linker Behavior:" to "Link all assemblies". Running the code will result in Exception and it will be of type default constructor for type XXX was not found.
Now, make a reference to the SomeGenericClass{string} in your code and the method will run just fine. The two added lines cause the compiler to include SomeGenericClass{string} in the binary. Note that the lines can be anywhere in the application that is compiled into the binary, they don't have to be in the same function.
public void InvokeGenericType()
{
// comment out the two lines below to make the code fail
var strClass = new SomeGenericClass<string>();
strClass.Execute("Test");
var type = typeof(SomeGenericClass<>).MakeGenericType (typeof(string));
var instance = Activator.CreateInstance (type);
var method = type.GetMethod ("Execute");
method.Invoke (instance, new object[]{"Test"});
}

C# Generic Method vs Casting

I'm writing a program in C# (3.5 at the moment, but likely to be adaptable to other versions as the need arises) that uses a simple plugin architecture to control input and output. Each plugin is a DLL that is loaded when the user chooses the plugins to use.
Since the actual plugin class isn't known until run time, I'm using reflection in a wrapper class to call methods and access properties of the plugins.
Up until now, I've been using the following to call methods on a plugin:
public object Method(string methodName, params object[] arguments) {
// Assumed variables/methods/exceptions:
// Dictionary<string, MethodInfo> Methods: a cache of MethodInfo's
// of previously called methods.
// NoSuchMethodException: thrown if an unknown/unreachable method is
// requested. The message member contains the invalid method name
// void LoadMethod(string methodName, params object[] arguments): responsible
// for retrieving the MethodInfo's, or throw a NoSuchMethodException
// object Plugin: an instance of the dynamically loaded class.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return Methods[methodName].Invoke(Plugin, arguments);
}
Which is used like:
string[] headers = (string[]) Plugin.Method("GetHeaders", dbName, tableName);
This works nicely, as long as the caller correctly casts the return value to the expected
type. Plugins must implement certain interfaces, so the caller should know this type.
After doing some further work with reflection however, the following alternate form occurred to me:
public T Method<T>(string methodName, params object[] arguments) {
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (Methods[methodName].ReturnType != typeof(T)) {
// Could also move this into LoadMethod to keep all the throwing in one place
throw new NoSuchMethodException(methodName);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
return (T) Methods[methodName].Invoke(Plugin, arguments);
}
This one is used like:
string[] headers = Plugin.Method<string[]>("GetHeaders", dbName, tableName);
This version essentially moves the casting into the Method method. The caller obviously still needs to know the expected return type, but that was always going to be the case. It doesn't work for void methods, but I can include a version of Method for that:
public void Method(string methodName, params object[] arguments) {
// Good for void methods, or when you're going to throw away the return
// value anyway.
if (!Methods.ContainsKey(methodName)) {
LoadMethod(methodName, arguments);
}
if (arguments != null && arguments.Length == 0) {
arguments = null;
}
Methods[methodName].Invoke(Plugin, arguments);
}
My question is - is one of these intrinsically better than the other (for a given value of 'better')? For instance, is one notably faster? Easier to understand? More supported?
I personally like the look of the latter, although I am a bit worried that my return type testing (Methods[methodName].ReturnType != typeof(T)) might be too simplistic. Interestingly, it was originally !(Methods[methodName].ReturnType is T), but that always seemed to fail.
The closest existing question to this I could find was Generic method to type casting, and some of the answers suggested that the latter method is more expensive than the former, but there's not much in the way of detail there (the question there is more towards implementation of the method rather than which is better).
Clarification: This is a hand-rolled, very limited plugin system, not using IPlugin. I'm more interested in the question of whether generic methods are inherently better/worse than expecting the caller to cast in this situation.
As to your question I think you should provide both. Simply have the generic version invoke the non-generic version. You get the best of both worlds. Regarding performance, consider how small the time it takes to cast an object is in comparison to dynamically invoking a method and building up and object array. It really is not worth taking performance into consideration here. I for one prefer the generic approach from a stylistic perspective but also consider that you could apply type constraints should the need arise.
public T Method<T>(string methodName, params object[] arguments)
{
return (T)Method(methodName, arguments);
}
Side Bar
I'm thinking that your implementation should be casting to the expected interface if I understand your design. You really should not be using reflection if you know what methods the plugins should support.
var plugin = (IPlugin)Activator.CreateInstance(pluginType);
var headers = plugin.GetHeaders(dbName, tableName);
You could try something a bit different and require the plugin to implement an interface that allows them to register custom runtime behavior.
public interface IPlugin
{
void Load(IAppContext context);
void Unload();
}
Your loading method could look like this.
void LoadPlugins(Assembly a)
{
var plugins =
a.GetTypes()
.Where(t => typeof(IPlugin).IsAssignableFrom(t))
.Select(t => (IPlugin)Activator.CreateInstance(t))
.ToList();
Plugins.AddRange(plugins);
foreach (var p in plugins)
{
p.Load(Context);
}
}

Why does adding beforefieldinit drasticly improve the execution speed of generic classes?

I'm working on a proxy and for generic classes with a reference type parameter it was very slow. Especially for generic methods (about 400 ms vs 3200 ms for trivial generic methods that just returned null). I decided to try to see how it would perform if I rewrote the generated class in C#, and it performed much better, about the same performance as my non-generic class code.
Here is the C# class I wrote:: (note I changed by naming scheme but not a heck of a lot)::
namespace TestData
{
public class TestClassProxy<pR> : TestClass<pR>
{
private InvocationHandler<Func<TestClass<pR>, object>> _0_Test;
private InvocationHandler<Func<TestClass<pR>, pR, GenericToken, object>> _1_Test;
private static readonly InvocationHandler[] _proxy_handlers = new InvocationHandler[] {
new InvocationHandler<Func<TestClass<pR>, object>>(new Func<TestClass<pR>, object>(TestClassProxy<pR>.s_0_Test)),
new GenericInvocationHandler<Func<TestClass<pR>, pR, GenericToken, object>>(typeof(TestClassProxy<pR>), "s_1_Test") };
public TestClassProxy(InvocationHandler[] handlers)
{
if (handlers == null)
{
throw new ArgumentNullException("handlers");
}
if (handlers.Length != 2)
{
throw new ArgumentException("Handlers needs to be an array of 2 parameters.", "handlers");
}
this._0_Test = (InvocationHandler<Func<TestClass<pR>, object>>)(handlers[0] ?? _proxy_handlers[0]);
this._1_Test = (InvocationHandler<Func<TestClass<pR>, pR, GenericToken, object>>)(handlers[1] ?? _proxy_handlers[1]);
}
private object __0__Test()
{
return base.Test();
}
private object __1__Test<T>(pR local1) where T:IConvertible
{
return base.Test<T>(local1);
}
public static object s_0_Test(TestClass<pR> class1)
{
return ((TestClassProxy<pR>)class1).__0__Test();
}
public static object s_1_Test<T>(TestClass<pR> class1, pR local1) where T:IConvertible
{
return ((TestClassProxy<pR>)class1).__1__Test<T>(local1);
}
public override object Test()
{
return this._0_Test.Target(this);
}
public override object Test<T>(pR local1)
{
return this._1_Test.Target(this, local1, GenericToken<T>.Token);
}
}
}
This is compiles in release mode to the same IL as my generated proxy here is the class that its proxying::
namespace TestData
{
public class TestClass<R>
{
public virtual object Test()
{
return default(object);
}
public virtual object Test<T>(R r) where T:IConvertible
{
return default(object);
}
}
}
There was one-exception, I was not setting the beforefieldinit attribute on the type generated. I was just setting the following attributes::public auto ansi
Why did using beforefieldinit make the performance improve so much?
(The only other difference was I wasn't naming my parameters which really didn't matter in the grand scheme of things.
The names for methods and fields are scrambled to avoid collision with real methods.
GenericToken and InvocationHandlers are implementation details that are irrelevant for sake of argument.
GenericToken is literally used as just a typed data holder as it allows me to send "T" to the handler
InvocationHandler is just a holder for the delegate field target there is no actual implementation detail.
GenericInvocationHandler uses a callsite technique like the DLR to rewrite the delegate as needed to handle the different generic arguments passed
)
EDIT::
Here is the test harness::
private static void RunTests(int count = 1 << 24, bool displayResults = true)
{
var tests = Array.FindAll(Tests, t => t != null);
var maxLength = tests.Select(x => GetMethodName(x.Method).Length).Max();
for (int j = 0; j < tests.Length; j++)
{
var action = tests[j];
Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < count; i++)
{
action();
}
sw.Stop();
if (displayResults)
{
Console.WriteLine("{2} {0}: {1}ms", GetMethodName(action.Method).PadRight(maxLength),
((int)sw.ElapsedMilliseconds).ToString(), j);
}
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
}
}
private static string GetMethodName(MethodInfo method)
{
return method.IsGenericMethod
? string.Format(#"{0}<{1}>", method.Name, string.Join<Type>(",", method.GetGenericArguments()))
: method.Name;
}
And in a test I do the following::
Tests[0] = () => proxiedTestClass.Test();
Tests[1] = () => proxiedTestClass.Test<string>("2");
Tests[2] = () => handClass.Test();
Tests[3] = () => handClass.Test<string>("2");
RunTests(100, false);
RunTests();
Where Tests is a Func<object>[20], and proxiedTestClass is the class generated by my assembly, and handClass is the one I generated by hand.
RunTests is called twice, once to "warm" things up, and again to run it and print to the screen. I mostly took this code from a post here by Jon Skeet.
As stated in ECMA-335 (CLI cpecification), part I, section 8.9.5:
The semantics of when and what triggers execution of such type
initialization methods, is as follows:
A type can have a type-initializer method, or not.
A type can be specified as having a relaxed semantic for its type-initializer method (for convenience below, we call this relaxed
semantic BeforeFieldInit).
If marked BeforeFieldInit then the type’s initializer method is executed at, or sometime before, first access to any static field
defined for that type.
If not marked BeforeFieldInit then that type’s initializer method is executed at (i.e., is triggered by):
a. first access to any static field of that type, or
b. first invocation of any static method of that type, or
c. first invocation of any instance or virtual method of that type
if it is a value type or
d. first invocation of any constructor for that type.
Also, as you can see from the Michael's code above, the TestClassProxy has only one static field: _proxy_handlers. Notice, that it is used only two times:
In the instance constructor
And in the static field initializer itself
So when BeforeFieldInit is specified, type-initializer will be called only once: in the instance constructor, right before the first access to _proxy_handlers.
But if BeforeFieldInit is omitted, CLR will place the call to the type-initializer before every TestClassProxy's static method invocation, static field access, etc.
In particular, the type-initializer will be called on every invocation of s_0_Test and s_1_Test<T> static methods.
Of course, as stated in ECMA-334 (C# Language Specification), section 17.11:
The static constructor for a non-generic class executes at most once
in a given application domain. The static constructor for a generic
class declaration executes at most once for each closed constructed
type constructed from the class declaration (§25.1.5).
But in order to guarantee this, CLR have to check (in a thread-safe manner) if the class is already initialized, or not.
And these checks will decrease the performance.
PS: You might be surprised that performance issues will gone once you change s_0_Test and s_1_Test<T> to be instance-methods.
First, if you want to learn more about beforefieldinit, read Jon Skeet's article C# and beforefieldinit. Parts of this answer are based on that and I'll repeat the relevant bits here.
Second, your code does very little, so overhead will have significant impact on your measurements. In real code, the impact is likely to be much smaller.
Third, you don't need to use Reflection.Emit to set whether a class has beforefieldint. You can disable that flag in C# by adding a static constructor (e.g. static TestClassProxy() {}).
Now, what beforefieldinit does is that it governs when is the type initializer (method called .cctor) called. In C# terms, type initializer contains all static field initializers and code from the static constructor, if there is one.
If you don't set that flag, the type initializer will be called when either an instance of the class is created or any of the static members of the class are referenced. (Taken from the C# spec, using CLI spec here would be more accurate, but the end result is the same.*)
What this means is that without beforefieldinit, the compiler is very confined about when to call the type initializer, it can't decide to call it a bit earlier, even if doing that would be more convenient (and resulted in faster code).
Knowing this, we can look at what's actually happening in your code. The problematic cases are static methods, because that's where the type initializer might be called. (Instance constructor is another one, but you're not measuring that.)
I focused on the method s_1_Test(). And because I don't actually need it to do anything, I simplified it (to make the generated native code shorter) to:
public static object s_1_Test<T>(TestClass<pR> class1, pR local1) where T:IConvertible
{
return null;
}
Now, let's look at the disassembly in VS (in Release mode), first without the static constructor, that is with beforefieldinit:
00000000 xor eax,eax
00000002 ret
Here, the result is set to 0 (it's done in somewhat obfuscated manner for performance reasons) and the method returns, very simple.
What happens with static the static constructor (i.e. without beforefieldinit)?
00000000 sub rsp,28h
00000004 mov rdx,rcx
00000007 xor ecx,ecx
00000009 call 000000005F8213A0
0000000e xor eax,eax
00000010 add rsp,28h
00000014 ret
This is much more complicated, the real problem is the call instruction, which presumably calls a function that invokes the type initializer if necessary.
I believe this the source of the performance difference between the two situations.
The reason why the added check is necessary is because your type is generic and you're using it with a reference type as a type parameter. In that case, the JITted code for different generic versions of your class is shared, but the type initializer has to be called for each generic version. Moving the static methods to another, non-generic type would be one way to solve the issue.
* Unless you do something crazy like calling instance method on null using call (and not callvirt, which throws for null).

Invoking Method on Object Instantiated From DLL

I am having some trouble with assemblies and DLL's.
instrument_ is declared as an object and I'm creating an instance of "PP150" from the dll whose path is specified by path_.
string className = ContineoProperties.getSingleton().getClassName(path_);
assembly_ = Assembly.LoadFrom(path_);
Type classType = assembly_.GetType("Instrument." + className);
instrument_ = Activator.CreateInstance(classType);
Later I to call the method isntrument_.instrumentCommand(cmd.getCommandName())
The error I get is with when i call the method.
'object' does not contain a definition for 'instrumentCommand'
The isntrument_ is created fine. its just the method call that's giving me a problem. The method does exist in the "PP150.dll". Do I need some DLLImport to allow it to recognize it as a function?
Thanks,
P
If object type is not known in compile time,
To call a method defined on an object, you must use Reflection.
MethodInfo mInfo = classType.GetMethod("instrumentCommand");
mInfo.Invoke(instrument_, new Object[] { _parameters});
The compiler is never going to recognize the methods on a type that you are loading via reflection (e.g. using Assembly.GetType() and Activator.CreateInstance()). Unless you have the type metadata available at build time, you will always get that error if you try to call methods that are not defined on Object itself.
You have two options for making that kind of method call. Both of them require you to give up type safety, the only difference is the amount of work required. In both cases, if you make a mistake, the compiler will not tell you -- you will get a runtime exception instead.
Declare instrument_ as dynamic instead of object. This, obviously, only works in .NET 4.0, but it accomplishes exactly what you're trying to do. The method call will be dispatched at runtime, so as long as the instance that instrument_ references actually has a method call with the appropriate name, it will work.
Use reflection to call the method. You're already using reflection to load the type, so you are halfway there. You would need to add something like this:
// The array of types is the parameter list; assuming instrumentCommand takes
// a string it would look like this:
MethodInfo method = classType.GetMethod("instrumentCommand", new Type[] { typeof(string) });
method.Invoke(instrument_, new object[] { cmd.getCommandName() });
This happens because Activator.CreateInstance returns an object. I would create a separate DLL for the interface which is implemented by the class you want to instantiate. Both the DLL containing this class, and the executable should reference the DLL containing the interface. This way you could cast the object returned by Activator.CreateInstance to the interface, and call its methods:
IInstrument.dll:
interface IInstrument
{
void instrumentCommand(string cmd);
}
Instrument.dll (add IInstrument.dll as reference):
class Instrument : IInstrument
{
public void instrumentCommand(string cmd)
{
// ... implementation ...
}
}
InstrumentApp.exe (add IInstrument.dll as reference):
class Program
{
public static void Main()
{
// ... load Instrument.dll into assembly object ...
// ... load the type from the assembly ...
IInstrument instrument_ = (IInstrument)Activator.CreateInstance(classType);
instrument_.instrumentCommand(cmd.getCommandName());
}
}
The most simple thing would be to link agains PP150.
If you did link against the dll you must use Assembly.LoadFile or Assembly.Load and not LoadFrom because the last one will cause the assembly load to load your assembly in the LoadFrom loader context which will alter type identity.
Suppose you load the Type T from Assembly A via LoadFrom and you link against A as well.
object CreateTypeFrom()
{
var A = Assembly.LoadFrom(#"xxxx");
return A.CreateInstance("T");
}
void Test()
{
object t = CreateTypeFrom();
T RealT = new T(); // no prob
T Castedt = (T)t; // this will throw an InvalidCastException
T isNull = t as T; // this will result in a null instance
}
As you can see although you did create two times an instance of T they cannot be casted to due to different loader context which will make the type pretty useless.
To get rid of these things you could simply use Reflection to create a proxy type which will forward your calls to the proxy type. If you are using .NET 4 you can take advantage of the DLR to find the best matching methods at runtime. The code below creats a Version object and returns it as dynamic object. Then I do call the Major property to an integer and print it out to console. This does work with no exceptions nor compile time errors if you are using .NET 4 or later.
dynamic CreateTypeFrom()
{
var assembly = typeof(string).Assembly;
return assembly.CreateInstance("System.Version", true, BindingFlags.CreateInstance, null, new object[] { 1, 2, 3, 4 }, null, null);
}
[TestMethod]
public void Test()
{
var t = CreateTypeFrom();
int major = t.Major;
Console.WriteLine(major);
}

Categories