Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

.Net Inheritance - Automatic dependency referencing behavior issue

I've come across a strange issue that I've just now noticed.

If you have a solution with 3 projects

** NOTE Edited after discussion **

Project LibA - Has a ClassA

namespace LibA
{
    public class ClassA
    {
        public override string ToString()
        {
            return "The logic in class A!";
        }
    }
}

Project LibB - Has a ClassB

using LibA;

namespace LibB
{
    public class ClassB
    {
        public ClassA a;

        public ClassB()
        {
            a = new ClassA();
        }

        public object Foo()
        {
            return a;
        }
    }
}

Project LibC - Has a ClassC

using LibB;

namespace LibC
{
    public class ClassC
    {
        public ClassB b;

        public ClassC()
        {
            b = new ClassB();
        }

        public object Foo()
        {
            return b.Foo();
        }
    }
}

Finally a test driver

using System;
using LibC;

namespace Shell
{
    class Program
    {
        static void Main(string[] args)
        {
            ClassC c = new ClassC();
            Console.WriteLine(c.Foo());
        }
    }
}

Now if you compile this, everything will work perfectly. If you examine the contents of LibC's binary folder, you'll see that it automatically rolled through the chain of dependencies to determine that it needed to pull in LibA and LibB

However, if you alter ClassB to inherit from class A such as

using LibA;

namespace LibB
{
    public class ClassB : ClassA
    {
        ClassA a;
    }
}

attempt to compile, you'll get the error

Error 2 The type 'LibA.ClassA' is defined in an assembly that is not referenced. You must add a reference to assembly 'LibA, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.

** Original Question **

Does anyone know why (whether it is msbuild or visual studio) it is smart enough to reference LibA when ClassA a member of ClassB, but it isn't smart enough to reference LibA when ClassA is the base class of ClassB?

I know it's nitpicky, but I would really appreciate some consistent behavior

** Amended Question with these observed tests **

I'm hearing what some define as "direct" or "indirect" references. However, direct is clearly not just the visibility scoping, it seems to be inheritance and actual usage of a type.

Without inheritance, the test driver is smart enough to resolve and automatically reference LibA, LibB and LibC.

There is a public member ClassA visible in ClassB and yet that alone doesn't produce the compilation/linking error.

The debugger definitely resolves ClassA from the test driver, so it clearly loaded the correct assembly.

So with all that in mind. I get the whole "direct" and "indirect" stuff now.

The thing that is still not clicking to me why the linker/compiler/IDE doesn't at least try to automatically reference the dependencies of a referenced library in an "direct" scenario? It's clearly smart enough to know the dependencies are there and reference them in an "indirect" scenario.

like image 949
Min Avatar asked Dec 14 '10 23:12

Min


1 Answers

This is consistent behaviour. The first one is a simple reference, the second one is inheritance.

If an assembly is compiled and a class inherits from a class in another assembly, that reference is required to construct it.

LibB only contains the information that is added in the class definition of ClassB, it doesn't copy everything from LibA (this would produce inconsistent code if LibA is updated and ClassA is changed while doing that, LibB would still contain the old information).

So to use an inherited class definition in LibC, it needs both the information from LibA (for ClassA) and LibB (ClassB) to construct it, thus a direct reference to LibA is needed.

In the example, all references to classes of different assemblies are private, thus only the next level is neeed (ClassC doesn't need to know about ClassA as there is no direct usage of that class). If the usage of ClassA in ClassB was a public field or propety, ClassC would have a direct reference to ClassA and would need a direct reference to that class definition as well (reference to LibA from LibC).

In a different form, this is also the case in the inheritance example. ClassC has a direct reference to ClassA (due to ClassB inherting from ClassA), thus a reference to the declaring assembly (namely LibA) is needed to construct the full class definition.

like image 127
Femaref Avatar answered Oct 12 '22 12:10

Femaref