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.