Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Inheritence in VB.Net: Must UI project refer all ALL other projects? 2

Status
Not open for further replies.

CosmicCharlie

Programmer
Jun 30, 2006
44
US
I have a problem making inheritance work the way I would expect it. Here is the scenario:


I have three projects that work together in a standard desktop solution. The first project is called DAL, which compiles to a DLL that works as a generic data layer that can talk to any database in my company’s system. It includes an abstract class called dalDataEntity, which defines an interface for data objects representing tables in my company’s databases. dalDataEntity defines a public, readonly property of ColumnCount. ColumnCount is not overridable. ColumnCount represents the number of columns in the table or resultset represented by a class derived from dalDataEntity.

The second project is called SalesData, which contains a bunch of classes that inherit from dalDataEntity. Each class corresponds to a table in our Sales database. Currently, SalesData has a project reference to DAL. ColumnCount is not referenced anywhere in the code for the classes in this project.

The third project is SalesUI, which is the presentation tier of our sales application. This project contains a project reference to SalesData and uses SalesData objects to do its work. However, it does NOT contain a reference to DAL.

Here is the problem: When I am writing code in SalesUI for a data object from SalesData, ColumnCount appears in Intellisense just like any accessible member of the data object. However, I get a design time error in my task list saying

Public Overridable Readonly Property ColumnCount() as Long is declared in project DAL.exe, which is not referenced by project SalesUI.exe

The only way I can use ColumnCount, apparently, is if I set a reference to DAL in SalesUI. Indeed, if I do set the reference, the property works just fine. But it seems to me that if VB.Net allowed true object oriented design, that SalesUI should not need a reference to DAL, since SalesData should take care of that relationship.

Can anyone shed light on this for me? What is the best approach to this situation? Do I have to set the reference to DAL, or is there a way to keep the UI and data layers truly separate?

Thank you.

Cosmic Charlie

 
Interesting find. I had never tried referencing a member of the parent of an object in a referenced project. I would expect as you did, that all of the parent members would be accessible through the child. I wonder if it is the same in C# or framework v2.0.

From what it sounds like, your layers are truly separate. The whole point of layers is to create logical abstraction, so that your GUI isn't performing data logic and your back end isn't altering the GUI directly. What it sounds like you are asking for is binary abstraction, where each logical segment is entirely contained with-in a single binary.

To get all metaphysical on it... If you were to paint a picture of the horizon, the sky above and the ground below would be separate, no matter if you painted on one canvas or three.

-Rick



VB.Net Forum forum796 forum855 ASP.NET Forum
[monkey]I believe in killer coding ninja monkeys.[monkey]
 
Hi, Rick.

You are correct, I am trying to achieve binary abstraction. I would seem to me that when a derived class is compiled, that the inherited members would be included in the compilation. Something must be, because the UI project sees the inherited members in Intellisense, but won't permit their use.

I did some more poking around on the web, and found that I am not the first person to experience this. Indeed, it has bedeviled many programmers. The best advice given is to simply set the reference like the error message suggests.

This link from the Microsoft website explains the obvious, along with the same solution:


What it does NOT explain is why this situation exists in the first place. This appears to violate OO design, but I suppose managing connections between multiple binary components isn't easy. I guess if the UI project needs to use an inherited member, it needs the project of the derived class to tell it where it got the member in the first place.

If anyone else has insights to share here (like WHY this happens) I welcome them. For now, though, I will proceed with putting that reference in.

Charlie
 
When a class in one assembly inherits from a class in another assembly, any client of the inheriting class must have a reference to both assemblies. So when you do this, you are basically creating a third "composite" assembly from the 2 dlls. The assembly where a class is located has no real relevance to iheritance. That is, there is nothing in the rules of inheritance that says classes must be in the same or separate assemblies. For example, all classes in .NET inherit from System.Object - therefore you always need a reference to the dll that defines System.Object, right?

Now, I think you might be confusing inheritance with layered architecture. I think your design goal for the UI to not reference the data-layer is good. I think the way for you to acheive that is to not have classes in the SalesData layer (your business-logic layer I assume) inherit from classes in the data layer. Rather, your SalesData classes should use the data layer internally, and provide a service to the UI layer that does not reveal anything about the data layer. This way, only the SalesData layer needs to reference the data layer.

Interesting topic..

Hope that helps

[blue]_______________________________________[/blue]
Business Logic:"AND when tweetle beetles battle with paddles in a puddle, they call it a tweetle beetle puddle paddle battle AND..." - Dr. Suess
 
Thank you, Dragonwell, for that analysis. You have an excellent point, that all or projects must reference System.Object, so the behavior I am complaining about here really is nothing new. Even though it appears to me to violate a principle of object orientated design, it is a fact of life that we have been living with since the advent of .Net.

Your observation that I am confusing layered architecture and inheritance helps clarify some issues surrounding how I am conceptualizing this design, and I will keep that in mind as I work on different projects. Your suggestion that SalesData not inherit anything from the data layer presents me with a problem, however. On its face, a self-imposed guideline that says we should avoid inheritance hierarchies that cross assembly boundaries sounds like a good idea. But in this case, the SalesData object inherits from an abstract base data class that is feature-rich and optimized for the data layer classes, so it makes sense to me to put it in the same assembly as the data layer. The dependency is just too strong to put it anywhere else, and the rapid development benefits of the base class are too great for me to dilute it somehow. I could put it in the same project as the data objects, but then I would need to create an identical copy of the base class for each data object project. (By convention, there is one project for each database in our system, and each project contains one data class for each table. We make exceptions to this structure where necessary, but that is the general layout.)

It seems to me that while I may prefer not to have my business layer inherit from the data layer, and I don’t like having to set a reference to the data layer in my UI layer, ultimately the benefit of having this powerful abstract class in one place makes the rest worth living with. However, if you have another idea on how I might make this work, I welcome it.
 
I would recommend leaving the base class in your base dll (as it was in General.dll in the GFC architecture). Cross assembly inheritance doesn't hurt anything (so far as I know), and it will save you redundant code and a huge headache worth of maintenance.

As for the inheritance... I'll jump into a bit of history here (Cosmic Charlie and I used to work together on a project that was similar to what he is describing here).

This is an (outdated) image of the architecture:
General.DLL held the Base_DO, BaseSQL_DO, and BaseSybase_DO classes. These objects contain all code that communicates with the database, CRUD functionality, underlying ADO.Net objects, reflection for assembly of SQL and stored proc parameters, etc...

There would then be a Sales.DLL that would contain a BusinessObjects and a DataObjects name space. The DataObjects namespace would contain classes that represent data entities (tables, views, store procs, etc). Each data object has a series or properties that are matched back to the data entity in the database. The moniker BusinessObjects is slightly misleading at this point. In the BO namespace there would be a series of classes that inherit from the classes in the DO namespace. These classes contain all of the business logic that specifically relates to that data entity. For example, if you had an invoice business object, you may want to be able to quickly retrieve Customer and Item data. So on the Invoice business object you may have a .GetCustomer() as Customer method that would return the customer business object that is related to that invoice business object.

In this architecture, the "GFC.BusinessOjects" namespace contained the business objects related to specific processes. We had a ton of reports, invoices, letters, processes, etc... Those processes were all contained in the BusinessObjects namespace. So where the Invoice business object mentioned above was the class that contained all of the business logic for the Invoice data entity, there could also be an Invoice business object in the GFC.BusinessObjects namespace that was actually a process that would generate a paper invoice to mail to the customer.

-Rick

VB.Net Forum forum796 forum855 ASP.NET Forum
[monkey]I believe in killer coding ninja monkeys.[monkey]
 
I second dragonwell's opinion, and very well explained too, I might add. Another star...

<there is nothing in the rules of inheritance that says classes must be in the same or separate assemblies

I believe a class with the friend modifier specified can only be subclassed by classes in its assembly, is that not so? If so, one could make a case that the modifiers (public, private, protected, etc.) are part of the rules of inheritance and this is something that should be pointed out.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top