Photo by Joshua Woroniecki on Unsplash

Limitations In Chaining References Across Class Libraries

So I discovered something interesting today when working with class libraries and references in .Net. It isn't necessarily a bug, but it is definitely not the behavior I would expect. Let me explain what I did, what I expected, and what actually happened.

What I Did

I was working in a large solution, let's call it SomeBigApplication. This particular application uses a fancy schmancy object deserializer that at it's heart allows you to map an indexed value in a delimited string to an object's property. It works something like this: mapper.Map<T>(index, mapTo => mapTo.Property).

There are other methods that do similar things for collections and whatnot, but you get the drift. There is a particular class I found myself rewriting from application to application, so being a good little developer I wrote an abstract class that contains the common properties that I'd need to map again and again across applications.

namespace Company.Objects.General{     public abstract class ReusableClass<T, U>     {          public T Qualifier { get; set; }          public U Value { get; set; }     }}

I was then able to inherit from this class for use in the application.

        namespace Company.Objects.SomeBigApplication{     public class ApplicationSpecificClass : ReusableClass<string, int>     {          public bool SomeSpecificProperty           {               get               {                    return SomeMethod(Qualifier);                }          }     }}

What I Expected

Class in hand, I then tried to map my delimited string resource into my new class.

mapper.Map<ApplicationSpecificClass>(index, asc => asc.Qualifier);if(applicationSpecificClass.SomeSpecificProperty){     // ...}

But low and behold, this didn't work. Wouldn't even compile. ApplicationSpecificClass does not contain a definition for Qualifier . But that's strange because SomeSpecificProperty can be found. And SomeSpecificProperty even references Qualifier , which the compiler is telling us can't be found! How odd. Let's see why we're getting this strange error.

What Happened

I included the name spaces in my code samples above for a reason. Each namespace exists in its own class library. Company.SomeBigApplication  references Company.Objects.SomeBigApplication  which in turn references Company.Objects.General. The mapper code is being executed within Company.SomeBigApplication. The compiler is, for whatever reason, only able to divine the signature to the first referenced class library. Because Qualifier  is defined in Company.Objects.General , which isn't referenced by Company.SomeBigApplication , the compiler either can't see or won't expose Qualifier and Value , even though the definitions within Company.Objects.SomeBigApplication  utilize those more generic definitions.

Luckily the fix was easy. All I had to do was reference Company.Objects.General  in Company.SomeBigApplication . This exposed the properties from the abstract class and all was well. But I think we've all learned an important lesson today on class library references. Well, if not important, an odd lesson.