Using a derived business object in a generic class

Using a derived business object in a generic class

Old forum URL: forums.lhotka.net/forums/t/12074.aspx


pearljam posted on Wednesday, July 17, 2013

So here is my setup. I have a class, CPData that derives from class PointData, that itself derives from BusinessBase<T>. I also have several other classes that derive from PointData,

I have a generic class, DataObjectCore<T> whose signature looks like this (I also have a member in that class of type BusinessBase<T>)

public class DataObjectCore<T> : where T : BusinessBase<T>

Now, in my class that uses DataObjectCore I am having problems. When I do this:

public class CPDataObject : DataObjectCore<CPData>

I get an error stating that the type CPData must be convertable to BusinessBase<CPData>. I understand what it's saying, but I am not sure of a way around it. If I change the type to be PointData it works, since that is the class that initially derived from BusinessBase. However I can't use PointData in this case. I have several other classes/business objects that pair up like CPData and CPDataObject.

This came about because we are converting our code from a custom in house business object framework to CSLA. Our in house solution didn't use generics so we are basically trying to minimize how much of our existing code gets changed. I do realize this isn't really specific to CSLA and it's more of an inheritance issue but I figured I'd star here first. Thanks!

JonnyBee replied on Wednesday, July 17, 2013

Inheritance can only go one straight line.

So you _could_ create a

There is no straight line in your example which is whay you get the exception.

Do not confuse generic constraint and  inheritance. 
In your sample CPDataObject inherits from DataObjectCore and there is no straight line up from DataObjectCore to CPData so that you can use that class as a generic constraint (or even cast the CPDataObject to CPData).

Once you create an actual (non-generic) type from a generic base class you can no longer inherit from that class.

You can however create Interfaces that may be implemented by many classes without inheritance so that you can cast the classes to that interface.

comp1mp replied on Sunday, July 21, 2013

JonnyBee

Once you create an actual (non-generic) type from a generic base class you can no longer inherit from that class.

I am confused.

are you saying the following is not supported?

Car : Vehicle

Vehicle : BusinessBase<Vehicle>

 

JonnyBee replied on Sunday, July 21, 2013

Yes,

You may however create

But then you will not be able to create an instance of Car<T> and to knowledge the best option is to create an ICar interface for common properties/methods.

comp1mp replied on Sunday, July 21, 2013

JonnyBee

But then you will not be able to create an instance of Car<T> and to knowledge the best option is to create an ICar interface for common properties/methods.

The problem with this is you cannot utilize scope, as everything is public. I could not create an internal method or property setter to be used only within the business assembly. With a concrete class I can.

I don't want to hijack the OPs  thread so I will post a separate question.

skagen00 replied on Sunday, July 21, 2013

I could be wrong but I do believe we established an equivalent of ICarInternal, a separate internal interface and that worked successfully.  Obviously one needs to cast to use it, but I believe it ended up being sufficient.

comp1mp replied on Sunday, July 21, 2013

My apologies to pearljam, as these posts may not provide a direct answer. Hopefully they provide at least some enlightenment with regards to CSLA and inheritance. Great screen name btw, I just busted out and listened to Ten for the first time in about 5 years after seeing  it...

skagen00

I could be wrong but I do believe we established an equivalent of ICarInternal, a separate internal interface and that worked successfully.  Obviously one needs to cast to use it, but I believe it ended up being sufficient.

Fantastic! It is not as clean as a simple concrete base class, as I would have to implement two interfaces ICar (public) and ICarInternal, plus the required cast as you point out. However, at first glance it appears to be viable a solution.

 [quote user="JonnyBee"]

Yes,

You may however create

Jonny, if I was just using plain old .NET without CSLA, the following would be allowed.

I am assuming then, that CSLA for whatever reason internally does not support the above implementation pattern.

My searching skills have failed me, is there a definitive thread that describes in detail why this is not supported by CSLA?

The only thing that comes to mind immediately for me is  that one could not use the RegisterProperty with lambda expressions. But surely this is not the only issue, because one could simply use the older RegisterProperty signatures.

JonnyBee replied on Sunday, July 21, 2013

Hi,

There is several places this would blow up in CSLA. 

All the places where the generic constraint T is used for input value or return value is not going to work as you expect..

Would you like to have a Save method on Edsel that returned an object of type Car?  

Would you be fine to have a Save method of both Edsel and Car call into the Save method of Car? 

comp1mp replied on Sunday, July 21, 2013

JonnyBee

Hi,

There is several places this would blow up in CSLA. 

All the places where the generic constraint T is used for input value or return value is not going to work as you expect..

Would you like to have a Save method on Edsel that returned an object of type Car?  

Would you be fine to have a Save method of both Edsel and Car call into the Save method of Car? 

Lol. Why yes, those things would make my work much more enjoyable Indifferent

In all seriousness, I first considered using inheritance in this manner this weekend, and while playing around the first thing I ran into was the RegisterProperty issue which, surprise, uses the generic constraint of T. The big picture should have clicked in my brain, but it didn't . My CSLA instincts are obviously no where close to yours.

Thanks for enlightening me!

 

comp1mp replied on Sunday, July 21, 2013

JonnyBee

Hi,

There is several places this would blow up in CSLA. 

All the places where the generic constraint T is used for input value or return value is not going to work as you expect..

Would you like to have a Save method on Edsel that returned an object of type Car?  

Would you be fine to have a Save method of both Edsel and Car call into the Save method of Car? 

OK now i am really confused. This is from a different thread.

[quote user="RockfordLhotka"]

To use inheritance in your classes, you must understand how CSLA manages properties, and you must adjust your coding appropriately. To avoid high levels of complexity, you really want to avoid having anything but your "leaf type" be non-generic. Although the alternative is possible, it means giving up all the simpler generic-based RegisterProperty overloads, and that is a common source of copy-paste errors in people's code.

It seems to me that Rocky is saying the inheritance pattern I described is possible in CSLA, but there are two issues.

Is he talking about 3.8.x and things have changed for 4.x?

JonnyBee replied on Monday, July 22, 2013

RockfordLhotka

To avoid high levels of complexity, you really want to avoid having anything but your "leaf type" be non-generic. Although the alternative is possible, it means giving up all the simpler generic-based RegisterProperty overloads, and that is a common source of copy-paste errors in people's code.

]

Rocky is recommending:

So that it is only the last leaf node that is non-generic.

I haven´t been successful in the other way. 

comp1mp replied on Monday, July 22, 2013

I agree this is his recommendation, but he does say the alternative is possible.

The compelling thing about the alternative is you get a nice concrete base class to work with instead of an interface. One of the many beautiful things about CSLA is the ability to write powerful code against the concrete BusinessBase. 

That quote is from two years ago. I would be interested if he still feels the same today, and if he was talking about earlier versions of CSLA or if he was referring to 4.x also. I am using 3.8.x for my current project and have no plans of ever moving to 4.x, at least for that project.

Maybe Rocky can chime in Smile.

Anyway,  thanks for the input Jonny!

skagen00 replied on Monday, July 22, 2013

Just a suggestion, but you can generally work against the interface like you can work against a base class -- just have your interface (ICar) inherit IBusinessBase, etc - and you'll typically have a lot of the properties/methods you'd like to utilize from the base classes without having to do any extra casting/etc.

 

 

 

Copyright (c) Marimer LLC