Search code examples
c#.net.net-core

How to use a class from Project A in Project C without direct reference in .NET Framework?


I have three C# library projects targeting .NET Framework 4:

  • Project A: Contains classA.
  • Project B: References Project A.
  • Project C: References Project B.

I want to use classA in Project C. However, it only works if I add a direct reference from Project C to Project A, which I want to avoid.

Is there a way to use classA in Project C without adding a direct reference to Project A, maintaining the current reference structure (B referencing A, and C referencing B)?

Here is a screenshot for what I am trying to do:

enter image description here

Thank you for your help!


Solution

  • In order to able to interact with a class you need to know it's API, i.e., its public members. To achieve this with dynamically loaded assemblies you can declare an interface that its exposed classes implement. You will need an additional assembly (a class library) containing the interface(s).

    Project "Contracts" (interfaces)
    ^
    |
    +-- Project "A"
    ^       ^
    |       |
    +-- Project "B"
    ^       ^
    |       |
    +-- Project "C"
    

    The projects A, B, C must also reference "Contracts"

    Example:

    // Project "Contracts"
    
    public interface IA
    {
        void DoA();
    }
    
    public interface IB
    {
        void DoB(IA a);
    }
    
    // Project "A"
    public class A : IA
    {
        public void DoA()
        {
            Console.WriteLine("A");
        }
    }
    
    // Project "B"
    public class B : IB
    {
        public void DoB(IA a);
        {
            Console.Write("B calling ");
            a.DoA();
        }
    }
    

    The main project can now load the assemblies dynamically, create objects and cast them to the known interfaces.

    See Create a .NET Core application with plugins where it is explained how you can load an assembly at runtime (this got a bit complicated in .NET Core and was easier in .NET Framework). I am not going to repeat all the details here. Once you have loaded the assembly, you can search for types implementing a given interface with

    foreach (Type type in assembly.GetTypes()) {
        if (typeof(IA).IsAssignableFrom(type))
        {
            if (Activator.CreateInstance(type) is IA a)
            {
                a.DoA();
            }
        }
    }