Strange behaviour when using dynamic types as method parameters - dynamic

I have the following interfaces that are part of an existing project. I'd like to make it possible to call the Store(..) function with dynamic objects. But I don't want to change the Interface hierarchy (if at all possible).
public interface IActualInterface
{
void Store(object entity);
}
public interface IExtendedInterface : IActualInterface
{
//Interface items not important
}
public class Test : IExtendedInterface
{
public void Store(object entity)
{
Console.WriteLine("Storing: " + entity.ToString());
}
}
and the following code:
IExtendedInterface extendedInterfaceTest = new Test();
IActualInterface actualInterfaceTest = new Test();
Test directTest = new Test();
dynamic employee = new ExpandoObject();
employee.Name = "John Smith";
employee.Age = 33;
employee.Phones = new ExpandoObject();
employee.Phones.Home = "0111 123123";
employee.Phones.Office = "027 321123";
employee.Tags = new List<dynamic>() { 123.4D, 99.54D };
try
{
extendedInterfaceTest .Store(employee);
}
catch (RuntimeBinderException rbEx)
{
Console.WriteLine(rbEx.Message);
}
//Casting as (object) works okay as it's not resolved at runtime
extendedInterfaceTest.Store((object)employee);
//this works because IActualInterface implements 'Store'
actualInterfaceTest.Store(employee);
//this also works okay (directTest : IProxyTest)
directTest.Store(employee);
When I call extendedInterfaceTest.Store(employee), it raises a runtime binder exception. Why does the interface type make a difference when it's the same underlying type? I can call it on IActualInterface and Type, but not IExtendedInterface?
I understand that when calling a function with a dynamic parameter, the resolution happens at runtime, but why the different behaviours?

What you need to remember is that dynamic resolution basically does the same process as static resolution, but at runtime. Anything that couldn't be resolved by the CLR won't be resolved by the DLR.
Let's take this small program, inspired by yours, and that doesn't use dynamic at all:
namespace ConsoleApplication38 {
public interface IActualInterface {
void Store(object entity);
}
public interface IExtendedInterface : IActualInterface {
}
public class TestInterface : IExtendedInterface {
public void Store(object entity) {
}
}
public abstract class ActualClass {
public abstract void Store(object entity);
}
public abstract class ExtendedClass : ActualClass {
}
public class TestClass : ExtendedClass {
public override void Store(object entity) {
}
}
class Program {
static void TestInterfaces() {
IActualInterface actualTest = new TestInterface();
IExtendedInterface extendedTest = new TestInterface();
TestInterface directTest = new TestInterface();
actualTest.Store(null);
extendedTest.Store(null);
directTest.Store(null);
}
static void TestClasses() {
ActualClass actualTest = new TestClass();
ExtendedClass extendedTest = new TestClass();
TestClass directTest = new TestClass();
actualTest.Store(null);
extendedTest.Store(null);
directTest.Store(null);
}
static void Main(string[] args) {
TestInterfaces();
TestClasses();
}
}
}
Everything compiles fine. But what did the compiler really generate? Let's see using ILdasm.
For the interfaces:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestInterface::Store(object)
We can see here that the C# compiler always generates calls for the interface or class where the method is defined. IActualInterface has a method slot for Store so it's used for actualTest.Store. IExtendedInterface doesn't, so IActualInterface is used for the call. TestInterface defines a new method Store, using the newslot IL modifier, effectively assigning a new slot in the vtable for that method, so it's directly used since directTest is of type TestInterface.
For the classes:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
For the 3 different types, the same call is generated because the method slot is defined on ActualClass.
Let's now see what we get if we write the IL ourselves, using the type we want rather than letting the C# compiler choosing it for us. I've modified the IL to look like this:
For interfaces:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.IActualInterface::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.IExtendedInterface::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestInterface::Store(object)
For classes:
// actualTest.Store
IL_0015: callvirt instance void ConsoleApplication38.ActualClass::Store(object)
// extendedTest.Store
IL_001d: callvirt instance void ConsoleApplication38.ExtendedClass::Store(object)
// directTest.Store
IL_0025: callvirt instance void ConsoleApplication38.TestClass::Store(object)
The program compiles fine with ILasm. However it fails to pass peverify and crashes at runtime with the following error:
Unhandled Exception:
System.MissingMethodException: Method
not found: 'Void
ConsoleApplication38.IExtendedInterface.Store(System.Object)'.
at
ConsoleApplication38.Program.TestInterfaces()
at
ConsoleApplication38.Program.Main(String[]
args)
If you remove this invalid call, the derived classes calls work fine without any error. The CLR is able to resolve the base method from the derived type call. However interfaces have no true representation in runtime, and the CLR isn't able to resolve the method call from the extended interface.
In theory, the C# compiler could emit the call directly to the correct class specified in the runtime. It would avoid problems about middle classes calls as seen on Eric Lippert's blog. However as demonstrated, this is not possible for interfaces.
Let's get back to the DLR. It resolves the method exactly the same way as the CLR. We've seen that IExtendedInterface.Store couldn't be resolved by the CLR. The DLR cannot either! This is totally hidden by the fact that the C# compiler will emit the right call, so always be careful when using dynamic unless you perfectly know how it works in the CLR.

Related

Class implementing Interface with subtype arguments

Why I cannot do that? I get compilation error.
public interface A {
void update(Object a);
}
public class B implements A{
void update(Long a) {
}
}
That is Java 8
I do not see here violating any OO principle.
That's really make my time difficult to implement a generic API...
(I try to get Generics out of the play because the generic API gets counter-intuitive)
You get a compilation error because void update(Long a) does not implement void update(Object a).
You can implement it as follows:
public class B implements A {
void update(Object o) {
if (!(o instanceof Long)) {
// possibly throw an exception
}
Long a = (Long) o;
...
}
}
A class that implements an interface must implement all the methods declared in the interface. The methods must have the exact same signature (name + parameters) as declared in the interface. The class does not need to implement (declare) the variables of an interface. Only the methods.
Source:
http://tutorials.jenkov.com/java/interfaces.html#:~:text=A%20class%20that%20implements%20an,Only%20the%20methods.

Cannot intercept the method with byte-buddy with #Advice.Origin Method

Using the following example, I am not able to intercept the methods call when I have #Advice.Origin Method method as an argument in my method.
public static void premain(String arguments, Instrumentation instrumentation) throws IOException {
new AgentBuilder.Default()
.type(ElementMatchers.nameEndsWith("Controller"))
.transform((builder, type, classLoader, module) -> {
return builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class));
}
).installOn(instrumentation);
}
#RuntimeType
public static Object intercept(#Advice.Origin Method method, #SuperCall Callable<?> callable) throws Exception {
System.out.println("intercept");
return callable.call();
}
If I remove #Advice.Origin Method method, the code starts working
#RuntimeType
public static Object intercept(#SuperCall Callable<?> callable) throws Exception {
System.out.println("intercept");
return callable.call();
}
There is a difference between #Advice.Origin and #Origin. Advice can do less then delegation but inlines its code. You need to adjust your imports.

Error activating HomeController

I have this class for instantiating my MVC controllers (I am using MVC 5 but not using WebApi)
public class NinjectControllerFactory : DefaultControllerFactory {
private readonly IKernel _ninjectKernel;
public NinjectControllerFactory(IKernel kernel)
{
_ninjectKernel = kernel;
}
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
return (controllerType == null) ? null : (IController)_ninjectKernel.Get(controllerType);
} }
In App_Start I have this class
public static class NinjectConfig
{
public static void RegisterInjections()
{
using (IKernel kernel = new StandardKernel())
{
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Bind<IAlbumService>().To<AlbumService>();
}
}
}
In the Global.asax I have
NinjectConfig.RegisterInjections();
When I run the application I get this error
Error activating HomeController
No matching bindings are available, and the type is not self-bindable.
Activation path:
1) Request for HomeController
Suggestions:
1) Ensure that you have defined a binding for HomeController.
2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
3) Ensure you have not accidentally created more than one kernel.
4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
5) If you are using automatic module loading, ensure the search path and filters are correct.
What am I doing wrong?
You seem to be disposing of the kernel pretty quickly (as soon as you have created it). Get rid of the using clause in your RegisterInjections method:
public static void RegisterInjections()
{
IKernel kernel = new StandardKernel();
ControllerBuilder.Current.SetControllerFactory(new NinjectControllerFactory(kernel));
kernel.Bind<IAlbumService>().To<AlbumService>();
}
When you dispose the kernel, you are basically killing everything you might have registered in it and by the time the runtime needs to instantiate your HomeController and asks the kernel for an instance of IAlbumSevrice, the kernel is already dead and cannot find such instance.

Ninject factory method with input parameter to determine which implementation to return

I am trying to find a way to have a factory class / method that would take in an object or some kind of identifier (string or type) then based off the input parameter determine which implementation of the interface to create and return.
how do I setup my factory method and register the dependency for the interface? following is what I have roughly.
public class ISampleFactory
{
public ISample GetSample(Type type)
{
// do something here to return an implementation of ISample
}
}
public class SampleA : ISample
{
public void DoSomething();
}
public class SampleB : ISample
{
public void DoSomething();
}
public interface ISample
{
void DoSomethin();
}
Have a look at ninject Contextual Bindings Documentation:
You can either use Named Bindings:
this.Bind<ISample>().To<SampleA>().Named("A");
this.Bind<ISample>().To<SampleB>().Named("B");
or a conditional binding with any of the already available extensions or write your own:
this.Bind<ISample>().To<SampleA>().When(...);
this.Bind<ISample>().To<SampleB>().When(...);
see https://github.com/ninject/ninject/wiki/Contextual-Binding

RhinoMocks Testing callback method

I have a service proxy class that makes asyn call to service operation. I use a callback method to pass results back to my view model.
Doing functional testing of view model, I can mock service proxy to ensure methods are called on the proxy, but how can I ensure that callback method is called as well?
With RhinoMocks I can test that events are handled and event raise events on the mocked object, but how can I test callbacks?
ViewModel:
public class MyViewModel
{
public void GetDataAsync()
{
// Use DI framework to get the object
IMyServiceClient myServiceClient = IoC.Resolve<IMyServiceClient>();
myServiceClient.GetData(GetDataAsyncCallback);
}
private void GetDataAsyncCallback(Entity entity, ServiceError error)
{
// do something here...
}
}
ServiceProxy:
public class MyService : ClientBase<IMyService>, IMyServiceClient
{
// Constructor
public NertiAdminServiceClient(string endpointConfigurationName, string remoteAddress)
:
base(endpointConfigurationName, remoteAddress)
{
}
// IMyServiceClient member.
public void GetData(Action<Entity, ServiceError> callback)
{
Channel.BeginGetData(EndGetData, callback);
}
private void EndGetData(IAsyncResult result)
{
Action<Entity, ServiceError> callback =
result.AsyncState as Action<Entity, ServiceError>;
ServiceError error;
Entity results = Channel.EndGetData(out error, result);
if (callback != null)
callback(results, error);
}
}
Thanks
Played around with this a bit and I think I may have what you're looking for. First, I'll display the MSTest code I did to verify this:
[TestClass]
public class UnitTest3
{
private delegate void MakeCallbackDelegate(Action<Entity, ServiceError> callback);
[TestMethod]
public void CallbackIntoViewModel()
{
var service = MockRepository.GenerateStub<IMyServiceClient>();
var model = new MyViewModel(service);
service.Stub(s => s.GetData(null)).Do(
new MakeCallbackDelegate(c => model.GetDataCallback(new Entity(), new ServiceError())));
model.GetDataAsync(null);
}
}
public class MyViewModel
{
private readonly IMyServiceClient client;
public MyViewModel(IMyServiceClient client)
{
this.client = client;
}
public virtual void GetDataAsync(Action<Entity, ServiceError> callback)
{
this.client.GetData(callback);
}
internal void GetDataCallback(Entity entity, ServiceError serviceError)
{
}
}
public interface IMyServiceClient
{
void GetData(Action<Entity, ServiceError> callback);
}
public class Entity
{
}
public class ServiceError
{
}
You'll notice a few things:
I made your callback internal. You'll need to use the InternalsVisisbleTo() attribute so your ViewModel assembly exposes internals to your unit tests (I'm not crazy about this, but it happens in rare cases like this).
I use Rhino.Mocks "Do" to execute the callback whenever the GetData is called. It's not using the callback supplied, but this is really more of an integration test. I assume you've got a ViewModel unit test to make sure that the real callback passed in to GetData is executed at the appropriate time.
Obviously, you'll want to create mock/stub Entity and ServiceError objects instead of just new'ing up like I did.