1

As shown in the code below, there are two interfaces IFoo defined in two different assemblies:

/// assembly A
interface IFoo {
    void DoSomething()
}

/// assembly B
interface IFoo {
    void DoSomething()

    void DoSomethingElse()
}

/// assembly C
class Bar : IFoo {
    public virtual void DoSomething()

    public virtual void DoSomethingElse()
}

Assuming assembly A and assembly B mistakenly have the same signature (either assembly weak name or strong name). Will the generated MSIL for class Bar be different depending on whether assembly A or assembly was used during build time?

In other words, suppose we build a project with assembly A and C at run time, is it okay to replace A with assembly B at run time? Or I will get exceptions like "IFoo.DoSomethingElse" is not implemented because during build process DoSomethingElseis considered a new method as opposed to implementing an existing method in the interface.

Lifu Huang
  • 11,930
  • 14
  • 55
  • 77
  • `AssemblyA.IFoo` is a different type than `AssemblyB.IFoo`. It doesn't matter that they have the same shape. If you want to dynamically construct an object, then there needs to be a type that both/all target types share (through inheritance). – Kenneth K. May 22 '19 at 17:12
  • Are you trying to intentionally swap out a DLL without recompiling the dependent program to change behavior, are you trying to ensure a DLL can't be changed at runtime by a malicious user altering its behavior, are you trying to protect against accidental changing of behavior due to coincidental name collisions, or something else? – Servy May 22 '19 at 17:15
  • @KennethK.as I have mentioned, these two assemblies have the same strong names. – Lifu Huang May 22 '19 at 17:26
  • @Servy, I am trying to intentionally swap out a DLL as a "hacky" hot fix. It's a complicated story, but in short, one of our services is currently throwing exception because of an upgraded dependency (which added one more method to its interface), but for some reasons, we cannot simply upgrade the dependency in runtime, so I am wondering if I could simply "add a new method" at compile time, and hopefully it would "implement" that interface at runtime. – Lifu Huang May 22 '19 at 17:30
  • 1
    The default interface method feature of C# v8 is meant to address this kind of problem. Too late, you do have to edit/rebuild that assembly. – Hans Passant May 22 '19 at 17:33
  • Thank you @HansPassant, I guess it's indeed too late. Just for the purpose of educating myself, I am wondering what's actually the difference between these two cases? i.e. why I have to rebuild although they "looked" the same from C# PoV? Is there some concept to distinguish between "new method" and "implement interface" at the MSIL level? – Lifu Huang May 22 '19 at 17:45

1 Answers1

1

Interface mappings are created at build time and if "assembly A" (1 method) used at build time than Foo class will only map one method in its interface map.

When instance of the class is created it will try to use the interface available at run time (which not necessary the same as one used at compile time as in your case) and will fail to map the new second method.

There is really no good way to solve it prior C# 8 - you either have to downgrade dependency so its interface is backward compatible or recompile your code with new version of dependency.

If this is expected to be common problem you may consider exposing base class from "assembly A" with default implementations of methods to allow adding methods to interface and derive your Foo from that class instead of interface.

As Hans Passant pointed out C# 8 introduces default interface methods to solve that exact problem.

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179
  • 1
    Default interface methods only solve the problem if you have the foresight to add a default implementation of the method in the first assembly, knowing that different implementors of it down the road may want to provide an implementation later, and that's even assuming there is some sensible default behavior for all instances of that interface. – Servy May 22 '19 at 19:23
  • @Servy - yes... but without it owner of the interface really stuck with adding `IFoo3:IFoo2:IFoo` new interfaces every time you need to add a method. (Whether this is good or bad is open for discussion... but I like having an option in addition to breaking change vs. new interface) – Alexei Levenkov May 22 '19 at 20:13
  • 1
    I'm not saying the feature is never useful, I'm just saying it doesn't solve the specific problem of wanting to add new functionality to an interface without needing to re-compile the code of the class implementing it (even if that class already has a suitable method). – Servy May 22 '19 at 20:59
  • We had a project that utilized a plugin strategy. Each plugin had to implement an interface and each plugin was its own assembly with its own build. Over time we had hundreds of these plugins. Then we wanted to add a new method. With default interface methods, could we not just add the new method to the interface with a default implementation and not have to recompile the hundreds of plugins? I believed that this feature was to solve this direct problem. – Scott Adams May 23 '19 at 00:04