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!
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.
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>
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.
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.
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.
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...
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.
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?
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
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!
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?
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.
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 .
Anyway, thanks for the input Jonny!
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