Digital Nirvana: Where does a callvirt of a non-existent method end up?

.net, c#, polymorphism

Solution

I believe your nirvana is filled with `MarshalByRefObjects`. They are handled uniquely by the framework, as it instruments all access to them in order to treat them as proxies for remote objects. The MBRO can't actually fulfill the offending code's request (since your v1 class doesn't support `DbParameter::set_ParameterName`), so it is taking the long road to nowhere. It isn't treated as a `MissingMethodException` since MBRO's are usually missing requested members, so the runtime is far more lenient.

However, if you tried changing your offending code to cast param as an `IDbDataParameter` before setting the property, I imagine it would work, since both v1 and v2 support that interface.

Problem

I call a property set-accessor on a library class which in its base class is marked as abstract. Now at runtime I force the application to run against another version of the library where the class implements only the underlying interfaces of the base class, but isn't derived from it. Interestingly, .NET will run the code, but setting the property has no effect. What's going on behind the scenes? Offending Code: ``` MyDbParameter param = new MyDbParameter(); param.ParameterName = "p"; Console.Out.WriteLine("ParameterName: " + param.ParameterName); ``` Library 2.0 (compiled) ``` public sealed class MyDbParameter : System.Data.Common.DbParameter { public override string ParameterName { get { return _name; } set { _name = value; } } //... } ``` Library 1.0 (run) ``` public sealed class MyDbParameter : MarshalByRefObject, IDbDataParameter, IDataParameter { public string ParameterName { get { return _name; } set { _name = value; } } //... } ``` Looking at the MSIL of the calling code I suppose the virtual call is resolved via the MetodTable of the base class: ``` IL_0001: newobj instance void [Library]Library.MyDbParameter::.ctor() IL_0006: stloc.0 IL_0007: ldloc.0 IL_0008: ldstr "p" IL_000d: callvirt instance void [System.Data]System.Data.Common.DbParameter::set_ParameterName(string) ``` But the base class does not exist when running the code - neither does `DbParameter.set_ParameterName()`. How is it possible that .NET doesn't complain about that? Which method actually gets called? UPDATE: As suggested by Samuel I've decompiled the class `System.Data.Common.DbParameter` and adopted it in both of my libraries. The behavior reproduces regardless of wherher I derive from `MarshalByRefObject` or comment all of it out - hereby I believe I have falsified Mason's answer. But during the process I've discovered what happens: In reality it is the setter/getter of some other property of `MyDbParameter` in Library 1 what is called, e.g. `Size` (which is of type `int`!) - it depends on the property order in code. In the previous case I implemented the setters of other properties so that I ignored the supplied values, therefore I could see no effect. Now if all of them have automatic getters/setters, the output of my code is actually correct. The question remains: Why doesn't .NET complain about the missing method at runtime?

Original source