Ninject get target type from IBinding - c#

I have an Interface that is implemented by several types. But before I do a kernel.GetAll<IAmServiceable>() I want to be able to ponder the target types of the injection.
I know the function kernel.GetBindings(typeof(IAmServiceable)) exists but this returns a list of IBinding's.
Does anyone know how I can get the target type from the IBinding?
I want to know the type that is bound to IAmServiceable before it gets instantiated.

I know it's probably a bit late now for your problem, but since i ran into this today, i thought others might too.
That's the code i finally came up with - i don't think its perfect (far from it), especially regarding performance, but it works for my case, and since i do not intend to call this method very often, it seems ok to me.
public Type GetBoundToType(IKernel kernel, Type boundType)
{
var binding = kernel.GetBindings(boundType).FirstOrDefault();
if (binding != null)
{
if (binding.Target != BindingTarget.Type && binding.Target != BindingTarget.Self)
{
// TODO: maybe the code below could work for other BindingTarget values, too, feelfree to try
throw new InvalidOperationException(string.Format("Cannot find the type to which {0} is bound to, because it is bound using a method, provider or constant ", boundType));
}
var req = kernel.CreateRequest(boundType, metadata => true, new IParameter[0], true, false);
var cache = kernel.Components.Get<ICache>();
var planner = kernel.Components.Get<IPlanner>();
var pipeline = kernel.Components.Get<IPipeline>();
var provider = binding.GetProvider(new Context(kernel, req, binding, cache, planner, pipeline));
return provider.Type;
}
if (boundType.IsClass && !boundType.IsAbstract)
{
return boundType;
}
throw new InvalidOperationException(string.Format("Cannot find the type to which {0} is bound to", boundType));
}

This is not possible. E.g what is the type In this case?
Bind<IX>().ToMethod(c => RandomBool() ? new Foo() : new Bar());

If you are working within a NinjectModule (or have access to an IKernel some other way) A nice simple approach would be:
var concreteType = Kernel.Get<InterfaceType>().GetType();
Obviously, the downside is you create an instance of the concrete type. It is nevertheless nice and simple and I think pretty robust. Obviously, if the interface derives from IDisposable you would use a using statement:
using(var obj = Kernel.Get<InterfaceType>())
{
var concreteType = obj.GetType();
.
.
.
}

Related

Adapter/Wrapper and equal references

I want to create a wrapper class for another type. This works fine until the point where it's necessary that (reference)-equal objects need to have (reference)-equal wrappers.
An example:
public interface ITest<T>
{
T GetInstance(bool createNew);
}
public class Test : ITest<Test>
{
private static Test instance;
public Test GetInstance(bool createNew)
{
if (instance == null || createNew)
{
instance = new Test();
}
return instance;
}
}
public class TestWrapper : ITest<TestWrapper>
{
private readonly Test wrapped;
public TestWrapper(Test wrapped)
{
this.wrapped = wrapped;
}
public TestWrapper GetInstance(bool createNew)
{
return new TestWrapper(wrapped.GetInstance(createNew));
}
}
Test.GetInstance returns always the same instance, as long as the parameter createNew is false.
By contrast TestWrapper.GetInstance returns always a new instance.
Since I want to be able to replace Test with TestWrapper, I search for a solution so that at the end, the wrapper returns a new instance only, if Test returns a new instance. However, the TestWrapper should have no knowledge about the internals of Test.
The test code is
private static void RunTest<T>(ITest<T> cls)
{
var i1 = (ITest<T>)cls.GetInstance(false);
var i2 = (ITest<T>)cls.GetInstance(false);
var i3 = (ITest<T>)cls.GetInstance(true);
var dic = new Dictionary<ITest<T>, bool>();
if (!dic.ContainsKey(i1)) dic.Add(i1, false); else dic[i1] = true;
if (!dic.ContainsKey(i2)) dic.Add(i2, false); else dic[i2] = true;
if (!dic.ContainsKey(i3)) dic.Add(i3, false); else dic[i3] = true;
Console.WriteLine(string.Join(", ", dic.Select(a => a.Value.ToString())));
}
The desired result is
True, False
and that's what you get if one passes new Test() to that method.
If you pass new TestWrapper(new Test()), you'll get
False, False, False
There is a solution based on a simple cache (Dictionary<Test, TestWrapper>) - but with that, I would hold many of the instances in memory without using them any further (and the GC could not collect those instances since there's a reference holding them).
I played around with WeakReferences a bit, but I can't spot a key that I can use to store the WeakReference - thus I have to iterate through the cache list and search for the correct instance which is slow. Besides, I've to implement this solution for every member (with it's very own cache) which seems not to be a great solution...
I hope I have adequately explained my problem ;) So, my questions are:
is there a way to cheat object.ReferenceEquals (that question is unrewarding)
what can I use (as a key for the cache) as an identifier for an object instance (so I can use WeakReference)
is there a better way to achieve a real adapter (where I can replace the adaptee with an adapter without headache)
I've no access to the Test class, and only limited access to the code that uses it (I'm able to pass an arbitrary instance as long it's implements the interface)
No, you can't cheat object.ReferenceEquals(). However, object.ReferenceEquals() is intentionally used very rarely, and usually in cases where things really do need to be reference-equal.
The runtime need it in order to get things right. E.g. if the instance is used as a key in an Dictionary<>
Actually, the runtime typically uses the .GetHashCode() and .Equals() behavior of the individual objects, but it just so happens that if you don't override that behavior in your classes, the base System.Object implementation of those methods relies on the object reference by default.
So if you have the ability to change the code for both the Test class and the TestWrapper class, you can override these equality methods in those classes to ensure that they recognize equivalent objects as equal.
An alternative (and usually better) approach would be to create an IEqualityComparer<> implementation to use in your specific use case. You mentioned keys in a Dictionary<>: you can provide an IEqualityComparer<> instance to the dictionary when it's created to have it test for equality in exactly the way you want.
var dict = new Dictionary<object, object(new TestsAndWrappersAreEqualComparer());
var test = Test.GetInstance(true);
var testWrapper = TestWrapper.GetInstance(true);
dict[test] = test;
Console.WriteLine(dict.ContainsKey(test)); // true

In TPL Dataflow, is it possible to change DataflowBlockOptions after block is created but before it is used?

... and have it take effect?
I'd like to defer setting the ExecutionDataflowBlockOptions.SingleProducerConstrained property until I'm ready to link the network together. (Because, I want to separate creating the blocks, with their semantics, from linking the network together, with its semantics.)
But as far as I can tell you can only set the ExecutionDataflowBlockOptions when the block is created (e.g., for TransformBlock, TransformManyBlock, etc, you pass it in to the constructor and it is not visible otherwise).
However ... it hasn't escaped my notice that the properties have public setters. So ... can I create the block with a placeholder instance of ExecutionDataflowBlockOptions and hold on to it so that I can later set SingleProducerConstrained=true if I desire, when linking the blocks together (and that it will take effect)?
(BTW, is there any way to tell if SingleProducerConstrained is having any effect other than measuring throughput?)
Update: #i3amon correctly pointed out in his answer this can't be done because dataflow blocks clone the DataflowBlockOptions you pass in and use that. But I did it anyway, using internal data structures I can access via reflection and dynamic. I put that in an answer below.
It isn't possible. Modifying the options after the fact won't work. The options are cloned inside the block's constructor. Changing the options later will have no effect.
You can see examples of that here and here and it's simple to verify:
var options = new ExecutionDataflowBlockOptions
{
NameFormat = "bar",
};
var block = new ActionBlock<int>(_ => { }, options);
options.NameFormat = "hamster";
Console.WriteLine(block.ToString());
Output:
bar
Let me answer my own question. Using information from DotNetInside's decompile of the Dataflow assembly, for example, TransformBlock here (thanks #i3amon again for the link to dotnetinside.com), and the very nice ExposedObject package at codeplex here (which I learned about at this blog post, I did the following:
The TPL Dataflow blocks all implement debugger visualizers via the DebuggerTypeProxy attribute, which, applied to a type, names another type to use in the Visual Studio debugger whenever the original type is to be displayed (e.g., watch window).
Each of these DebuggerTypeProxy-named classes are inner classes of the dataflow block the attribute is attached to, usually named DebugView. That class is always private and sealed. It exposes lots of cool stuff about the dataflow block, including its genuine (not a copy) DataflowBlockOptions and also - if the block is a source block - an ITargetBlock[], which can be used to trace the dataflow network from its start block after construction.
Once you get an instance of the DebugView you can use dynamic via ExposedObject to get any of the properties exposed by the class - ExposedObject lets you take an object and use ordinary method and property syntax to access its methods and properties.
Thus you can get the DataflowBlockOptions out of the dataflow block and change its NameFormat, and if it is an ExecutionDataflowBlockOptions (and you haven't yet hooked up the block to other blocks) you can change its SingleProducerConstrained value.
However you can't use dynamic to find or construct the instance of the inner DebugView class. You need reflection for that. You start by getting the DebuggerTypeProxy attribute off your
dataflow block's type, fetch the name of the debugging class, assume it is an inner class of
the dataflow block's type and search for it, convert it to a closed generic type, and finally
construct an instance.
Be fully aware that you're using undocumented code from the dataflow internals. Use your own
judgement about whether this is a good idea. In my opinion, the developers of TPL Dataflow did a lot of work to support viewing these blocks in the debugger, and they'll probably keep it up. Details may change, but, if you're doing proper error checking on your reflection and dynamic use of these types, you will be able to discover when your code stops working with a new version of TPL Dataflow.
The following code fragments probably don't compile together - they're simply cut&pasted out of my working code, from different classes, but they certainly give you the idea. I made it work fine. (Also, for brevity, I elided all error checking.) (Also, I developed/tested this code with version 4.5.20.0 only of TPL dataflow, so you may have to adapt it for past - or future! - versions.)
// Set (change) the NameFormat of a dataflow block after construction
public void SetNameFormat(IDataflowBlock block, string nameFormat)
{
try
{
dynamic debugView = block.GetInternalData(Logger);
if (null != debugView)
{
var blockOptions = debugView.DataflowBlockOptions as DataflowBlockOptions;
blockOptions.NameFormat = nameFormat;
}
}
catch (Exception ex)
{
...
}
}
// Get access to the internal data of a dataflow block via its DebugTypeProxy class
public static dynamic GetInternalData(this IDataflowBlock block)
{
Type blockType = block.GetType();
try
{
// Get the DebuggerTypeProxy attribute, which names the debug class type.
DebuggerTypeProxyAttribute debuggerTypeProxyAttr =
blockType.GetCustomAttributes(true).OfType<DebuggerTypeProxyAttribute>().Single();
// Get the name of the debug class type
string debuggerTypeProxyNestedClassName =
GetNestedTypeNameFromTypeProxyName(debuggerTypeProxyAttr.ProxyTypeName);
// Get the actual Type of the nested class type (it will be open generic)
Type openDebuggerTypeProxyNestedClass = blockType.GetNestedType(
debuggerTypeProxyNestedClassName,
System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic);
// Close it with the actual type arguments from the outer (dataflow block) Type.
Type debuggerTypeProxyNestedClass =
openDebuggerTypeProxyNestedClass.CloseNestedTypeOfClosedGeneric(blockType);
// Now create an instance of the debug class directed at the given dataflow block.
dynamic debugView = ExposedObject.New(debuggerTypeProxyNestedClass, block);
return debugView;
}
catch (Exception ex)
{
...
return null;
}
}
// Given a (Type of a) (open) inner class of a generic class, return the (Type
// of the) closed inner class.
public static Type CloseNestedTypeOfClosedGeneric(
this Type openNestedType,
Type closedOuterGenericType)
{
Type[] outerGenericTypeArguments = closedOuterGenericType.GetGenericArguments();
Type closedNestedType = openNestedType.MakeGenericType(outerGenericTypeArguments);
return closedNestedType;
}
// A cheesy helper to pull a type name for a nested type out of a full assembly name.
private static string GetNestedTypeNameFromTypeProxyName(string value)
{
// Expecting it to have the following form: full assembly name, e.g.,
// "System.Threading...FooBlock`1+NESTEDNAMEHERE, System..."
Match m = Regex.Match(value, #"^.*`\d+[+]([_\w-[0-9]][_\w]+),.*$", RegexOptions.IgnoreCase);
if (!m.Success)
return null;
else
return m.Groups[1].Value;
}
// Added to IgorO.ExposedObjectProject.ExposedObject class to let me construct an
// object using a constructor with an argument.
public ExposedObject {
...
public static dynamic New(Type type, object arg)
{
return new ExposedObject(Create(type, arg));
}
private static object Create(Type type, object arg)
{
// Create instance using Activator
object res = Activator.CreateInstance(type, arg);
return res;
// ... or, alternatively, this works using reflection, your choice:
Type argType = arg.GetType();
ConstructorInfo constructorInfo = GetConstructorInfo(type, argType);
return constructorInfo.Invoke(new object[] { arg });
}
...
}

Creating a new instance of an object each time method is called

Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
This code is fairly simple; it just opens a new window and sets the DataContext of the new window. The problem I'm having is that if I execute this twice, the content of the first instance will be overwritten and be set to that of the second since adventurerWindowVM is the DataContext of both windows and it is overwritten each time this code is called. I'm looking for a way to prevent this; I'd like to be able to open multiple windows using this message and have each of them be unique, but thus far I haven't figured out a way to do so. Any advice would be greatly appreciated. I apologize for the vague title; I was unsure of what to name this question. (Also, I know that this isn't a method. What would this block of code be called?)
Update: I'm using MVVM Light and my code is based off of an example somebody provided for me in this answer: https://stackoverflow.com/a/16994523/1667020
Here is some code from my ViewModelLocator.cs
public ViewModelLocator()
{
_main = new MainViewModel();
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
SimpleIoc.Default.Register<GameViewModel>();
SimpleIoc.Default.Register<AdventurerViewModel>();
}
Having given the other answer, I guess I can say the IoC container used here is just SimpleIoC from MvvmLight and to get a new instance of the VM on every GetInstance(...) all you need to do is pass in a unique key every time when trying to resolve an instance of the VM.
So you can switch
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>();
to
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(System.Guid.NewGuid().ToString());
However as mentioned by the author of MVVMLight Here these VM's will get cached and we need to get rid of them when no longer needed. In your case probably when the Window is closed.
Thus I'd have that entire lambda something like:
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var uniqueKey = System.Guid.NewGuid().ToString();
var adventurerWindowVM = SimpleIoc.Default.GetInstance<AdventurerViewModel>(uniqueKey);
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Closed += (sender, args) => SimpleIoc.Default.Unregister(uniqueKey);
adventurerWindow.Show();
});
Note:
While this is somewhat longer 3 lines compared to just creating a new VM yourself with (new AdventurerViewModel()) I still favor this because if you use an IoC container to manage LifeTime of your VM's, then have it manage them completely. Don't really like mix-n-match when not needed. Rather keep the IoC Container doing what it's meant to do.
If you need more control over VM injection and Life-time management look at more sophisticated Ioc controllers such as Unity. SimpleIoC was just meant to be a simple get your feet "wet" in IoC kind of container and it does a very good job in that regard.
I think you are trying to use the same instance of your ViewModel with multiple views. So the views will obviously overwrite each others viewmodel contents.
What if you do this;
Messenger.Default.Register<OpenWindowMessage>(this, message =>
{
var adventurerWindowVM = new AdventurerViewModel();
adventurerWindowVM.Adv = message.Argument;
var adventurerWindow = new AdventurerView()
{
DataContext = adventurerWindowVM
};
adventurerWindow.Show();
});
It's a method call, passing in an anonymous method using a lambda expression.
It looks like you are getting your AdventurerViewModel from some sort of IoC container. How is the IoC container configured? In particular, what is the scope of the objects it gives you back? If you have the IoC configured to create objects in singleton scope, for example, then you will always get back a reference to the same object each time. You may need to configure the scope of the object in your IoC container so that it gives you back a fresh copy every time.
How you do that will depend on your IoC container. Without knowing which IoC framework you are using or seeing its configuration, it's impossible to make any further comment.
My advice would be to create an extension method for SimpleIOC. Something like this:
public static T CreateInstance<T>(this SimpleIoc simpleIoc)
{
// TODO implement
}
You already know the method to get the same instance; extended SimpleIoc with a method to create a new instance:
T instance = SimpleIoc.Default.GetInstance<T>();
T createdInstance = SimpleIoc.Defalt.CreateInstance<T>();
If you are not familiar with extension methods, see Extension Methods Demystified
The implementation:
Of type T, get the constructor.
If there is more than one constructor: either throw exception, or decide which constructor to use. Simple method: use the same method that is used in SimpleIoc.GetInstance, with an attribute. More elaborate method: try to find out if you can find registered elements that match one of the constructors. This is not explained here.
Once you've found the constructor that you need, get its parameters.
Ask SimpleIoc for instances of this parameter, or if they should be new also, ask SimpleIoc to create new instances.
CreateInstance
.
public static T CreateInstance<T>(this SimpleIoc ioc)
{
return (T)ioc.CreateInstance(typeof(T));
}
public static object CreateInstance(this SimpleIoc ioc, Type type)
{
ConstructorInfo constructor = ioc.GetConstructor(type);
IEnumerable<object> constructorParameterValues = ioc.GetParameters(constructor);
constructor.Invoke(constructorParameterValues.ToArray());
}
To decide which constructor to use:
private static ConstructorInfo GetConstructor(this SimpleIoc ioc, Type type)
{
ConstructorInfo[] constructors = type.GetConstructors();
ConstructorInfo constructorToUse;
if (constructorInfo.Length > 1)
{
// Decide which constructor to use; not explained here
// use Attribute like SimpleIoc.GetInstance?
// other method: use SimpleIoc.IsRegistered to check which Parameters
// are registered: use ConstructorInfo.GetParameters()
constructorToUse =
}
else
constructorToUse = constructoInfo[0];
return constructorToUse;
}
To get the values of the parameters in the constructor, we need to decide whether we want existing values from Ioc, or create new values:
public static IEnumerable<object> GetParameterValues(this simpleIoc ioc,
ConstructorInfo constructor)
{
IEnumerable<Type> parameterTypes = contructor.GetParameters()
.Select(parameter => parameter.ParameterType);
return ioc.GetInstances(parameterTypes);
}
public static IEnumerable<object> GetInstances(this SimpleIoc ioc,
IEnumerable<Type> types)
{
// TODO: decide if we want an existing instance from ioc,
// or a new one
// use existing instance:
return types.Select(type => ioc.GetInstance(type));
// or create a new instance:
return types.Select(type => ioc.CreateInstance(type));
}
This seems like a lot of code, but most of it is comment and most methods are one liners.

How do I get arguments passed to a data access layer that uses System.Action as an input parameter?

I'm trying to create some unit tests for an application I've recently inherited. Currently using NSubstitute because that's what the previous programmer used, but I'm not attached to it.
The method I'm testing calls the DataService class' Create method.
Calling Create Method
var contactProductLink = this.dsService.Create<ContactProductLink>(x =>
{
x.ContactRoleId = prod.RoleId;
x.ContactId = contactViewModel.ContactId;
x.ProductId = prod.ProductId;
x.Active = true;
x.InsertDate = DateTime.Now;
x.InsertUserId = user.employeeId;
x.UpdateDate = DateTime.Now;
x.UpdateUserId = user.employeeId;
});
DataService Create Method:
public TEntity Create<TEntity>(Action<TEntity> propertySetter = null) where TEntity : class
{
var tEntity = this.Context.Create<TEntity>();
if (propertySetter != null)
{
propertySetter(tEntity);
}
return tEntity;
}
The approach I've taken (and maybe there's a better way) is to use NSubstitute to mock the DataService. When I'm doing my assertions at the end, I'm checking to make sure that the Create method was called:
mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());
However, I'd like to also verify the input that was sent to the method is correct, and here's where I'm running into trouble. I can get the System.Action object that was passed to the Create method, but I can't figure out how to pull out the parameters (such as ContactRoleId, ContactId, etc. as posted in the calling create method code snippet).
So after all of that what I'm asking is:
How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?
Is there a better way to do this than what I'm currently trying to do?
Solution
//Arrange
mockDataSupplierService.Create<ContactProductLink>(Arg.Do<Action<ContactProductLink>>(x=> actionToPopulateEntity = x));
//Assert
mockDataSupplierService.Received().Create<ContactProductLink>(Arg.Any<Action<ContactProductLink>>());
var entity = new ContactProductLink();
actionToPopulateEntity.Invoke(entity);
Assert.AreEqual(ExpectedContactId, entity.ContactId);
How can I access those input parameters so I can verify the correct arguments are being passed to the data service? Is it even possible?
Essentially you can't, as it is not possible to extract "code" details from action (consider what happens when you pass an action that doesn't set any properties - this is totally legal, but would break hypothetical mechanism).
However, you can try this instead:
Create entity with initial values
Use Arg.Invoke argument, telling NSubstitute to use chosen object as action parameter
Verify that entity properties values changed
For example:
// Arrange
var entity = new ContactProductLink
{
ContactRoleId = // ...
// ...
};
mockDataSupplierService
.Create<ContactProductLink>(Arg<ContactProductLink>.Invoke(entity));
// Act
// ...
Assert.That(entity.ContactRoleId, Is.EqualTo(2));
// ...

How to decide at runtime which type to pass as a generic parameter?

I have several message queues that have specific messages on them.
I've created classes for these messages using xsd.exe.
I can receive a message syncronously and deseriazlise it with this method:
public oneOfMyTypes DeserializeMessage(XDocument message)
{
var serializer = new XmlSerializer(typeof(oneOfMyTypes));
var entity = (oneOfMyTypes)serializer.Deserialize(message.CreateReader());
return entity;
}
I then persist the entity via Fluent NHibernate.
So I've got about five message queues that all have their own type of message.
I would like to keep this little processor app maintainable, so that adding more message queues and message types doesn't become a pain.
So I have a list of queue names in my app.config that I use to create the message queues on start up and then I want to wire up a single method to the .ReceiveCompleted event of all queues:
void queue_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
var queue = (MessageQueue)sender;
var message = queue.EndReceive(e.AsyncResult);
var body = message.Body.ToString();
var xml = XDocument.Parse(body);
var queueName = queue.QueueName;
Type entityType = GetTypeFromQueueName(queueName);
entityType entity = DeserializeMessage<entityType>(xml);
var repository = new LogRepository();
repository.AddEntity<entityType>(entity);
}
private T DeserializeMessage<T>(XDocument message)
{
var serializer = new XmlSerializer(typeof(T));
var entity = (T)serializer.Deserialize(message.CreateReader());
return entity;
}
public Type GetTypeFromQueueName(string queueName)
{
switch (queueName)
{
case "some-message-queue-name":
return typeof (oneOfMyTypes);
}
}
But when I try to pass entityType to the generic methods I get "Type or namespace name expected".
I'm probably doing something really silly, but I can't figure out how this should work.
I've tried using the dynamic keyword and also .MakeGenericType but no luck.
I've also looked at:
Dynamic Generic declaration of type T
Function returning a generic type whose value is known only at runtime
Determining a Generic Type at Runtime in Non-Generic Class
How to pass variable of type "Type" to generic parameter
But I'm still not getting it ... help?
Unfortunately, generics are not meant to function dynamically like this. Generic parameters must be defined at design time. It's been a while since I've used NHibernate, but isn't there a way to insert entities with a syntax like:
repository.AddEntity(entity, typeof(myEntityType));
EDIT:
or
Session.SaveOrUpdate(object);
This link should help you
http://todotnet.com/post/2006/11/13/Instantiating-Generic-Types-at-runtime.aspx
You should be able to go from the link i posted to call the methode through reflection.
See the following link:
http://www.victorchen.info/call-static-method-with-a-string-name/
So basically when you've created your generic Type, you then grab the MethodInfo of your static method and then call the Invoke method on the MethodInfo object.
(i haven't actually tried this but in theory i believe it should work)

Categories

Resources