Subclassing

Subclassing

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


DeHaynes posted on Monday, September 18, 2006

   As I am looking to subclass the CSLA framework, I have the concept down, but I have never actually done it.  Does anyone know of a place that I could go to in order to help point out the pitfalls and standard way of doing things?

 

Thanks

RockfordLhotka replied on Monday, September 18, 2006

This active thread is covering the same topic and may be of interest

http://forums.lhotka.net/forums/thread/6349.aspx

DeHaynes replied on Monday, September 18, 2006

THANKS!  :)

Michael Hildner replied on Monday, September 18, 2006

Hey Tim,

I just finished doing this against the 2.0.3 version. Was pretty easy, but I did get a little confused with the generics business. I can send to you if you'd like, or we can compare.

Regards,

Mike

DeHaynes replied on Monday, September 18, 2006

Generics is what is messing me up too.  Can you reply to this and attach a zipped copy of just BusinessBase<T>?  I want to figure it out as much as I can so it sticks. 

 

Thanks a ton.

mr_lasseter replied on Tuesday, September 19, 2006

I am stuggling with this as well.  Would it be possible for you to post your BusinessBase(of T)?

Michael Hildner replied on Tuesday, September 19, 2006

Apologies Tim, I missed your post last night.

Keep in mind I'm not really sure what I'm doing either, any comments appreciated. I'm sure you'll want to change the namespace and class name.

using System;

using System.Collections.Generic;

using System.Text;

using Csla;

namespace Buoy.BusinessObjects203

{

[Serializable()]

public abstract class BuoyBusinessBase<T> :

BusinessBase<T>

where T : BuoyBusinessBase<T>

{

// We may want to mark a new object as clean, so that way

// it won't get saved if the user hasn't modified any

// properties.

public virtual void MarkAsClean()

{

this.MarkClean();

}

}

}

ajj3085 replied on Tuesday, September 19, 2006

I don't think that MarkAsClean should be public in scope.

The reason is that the object should be managing its own state, and the client should not be deciding if the object is dirty or clean.  Exposing this method is breaking encapsulation.

You should note that the default Save method of BusinessBase will NOT call save if the object is 'clean.'  I don't know what reason you have for marking the object clean to prevent saving, but I'm sure there's a better way.

Michael Hildner replied on Tuesday, September 19, 2006

Hey Andy,

Thanks, just the type of comments I'm looking for.

The reason I want to mark a new object as clean came from this thread http://forums.lhotka.net/forums/thread/2477.aspx

Basically, I don't want to prompt the user with "Do you want to save changes" if it's a new object and the user hasn't modified anything. In that case the object should not be saved at all.

I'm not sure if this should be done by the bo itself or the UI, as it seems like it's a UI function, but I'm not sure.

Thanks,

Mike

ajj3085 replied on Tuesday, September 19, 2006

Ahh.   I think a better, but slightly more complex solution, would be to override various items in BusinessBase.

private bool propertyChanged = false;

public override IsDirty {
     return propertyChanged && base.IsDirty;
}

protected override PropertyHasChanged( string propName ) {
   propertyChanged = true;
   base.PropertyHasChanged( propName );
}

You could encapsulate this in your BouyBusinessBase. 

This is just off the top of my head though, so take it with a grain of salt.

HTH
Andy

DeHaynes replied on Tuesday, September 19, 2006

Ok, I am confused.

public abstract class BuoyBusinessBase<T> : BusinessBase<T> where T : BuoyBusinessBase<T>

I thought this says BuoyBusinessBase<T> inherits from BusinessBase<T> Where T is type BuoyBusinessBase<T>?

If that is true, it seems like a circular reference.

Michael Hildner replied on Tuesday, September 19, 2006

Tim,

I'm no expert in generics, honestly I'm not really sure how that works - maybe someone can explain?

When I tried to subclass the CSLA classes, it took me a while to even compile it :) - I could very well be doing something wrong.

But, if you look at BusinessBase<T>, it's just about the same:

public abstract class BusinessBase<T> : BusinessBase where T : Csla.BusinessBase<T>

I'd love to get a good explanation on this.

Mike

DeHaynes replied on Tuesday, September 19, 2006

What I have read so far is that when you inherit from a generic class, you have to repeat any constraints.  So If you are inheriting from:

[Serializable()]
public abstract class BusinessBase<T> : Core.BusinessBase, Core.ISavable where T : BusinessBase<T>

The constraint here is       where T : BusinessBase<T>

So when I inherit from it, I need to do the following

[Serializable()]
public abstract class ANBOBusinessBase<T> : BusinessBase<T> where T : BusinessBase<T>

So that explains how to do it, but I still want to know what the

 where T : BusinessBase<T>

in the first declaration means.

 

RockfordLhotka replied on Tuesday, September 19, 2006

I do use a "recursive" generic when defining BusinessBase(Of T) - see Chapter 4 for some discussion of this as well. I also use a constraint to ensure that someone can't just instantiate a BusinessBase<T>, but rather that they must subclass it first.

If you want to create your own base classes, you need to do the same thing - both in terms of the recursive generic, and the constraint - which also, then, satisfies my constraint in CSLA itself.

[Serializable]
public abstract class MyNewBase<T> : BusinessBase<T> where T : MyNewBase<T>

Since MyNewBase inherits from BusinessBase<T>, the CSLA constraint is satisfied. And the new constraint on this class does the same thing as mine: ensuring that MyNewBase can only be used as a base class for a T. So a subclass is:

[Serializable]
public class Customer : MyNewBase<Customer>

While it will work for you to constraint T to BusinessBase<T>, that's not really the intent. The intent of the constraint is to force a subclass to pass itself as T - to force T to inherit from MyNewBase.

DansDreams replied on Tuesday, September 19, 2006

RockfordLhotka:
The intent of the constraint is to force a subclass to pass itself as T - to force T to inherit from MyNewBase.

I think I can see how that would only sound more confusing.

You could interpret what you said as simply "to force a subclass of MyNewBase to inherit from MyNewBase."  Sounds kinds of silly expressed that way, and that would lead to confusion because we know this really isn't silliness.

If I'm understanding this correctly (and I am NO generics expert) I think the two significant points are:

  1. You need/want to use a constraint to control how the class is used.
  2. Since the constraint you want to use is the class itself in this case, you have to use the generic signature of the class which includes the <T>

 

skagen00 replied on Tuesday, September 19, 2006

It means that T needs to be a decendent of BusinessBase<T>.

Thus I couldn't do this:

public class Individual : BusinessBase<string>

 

 

JoeFallon1 replied on Tuesday, September 19, 2006

The VB version of a company level Base class looks like this:

===================================================

<Serializable()> _

Public MustInherit Class MyBusinessBase(Of T As MyBusinessBase(Of T))

  Inherits BusinessBase(Of T)

===================================================

Then a regular Root Bo would look like this:

<Serializable()> _

Public Class Acct

  Inherits MyBusinessBase(Of Acct)

===================================================

DeHaynes replied on Tuesday, September 19, 2006

Thanks you two.  :)

 

DeHaynes replied on Tuesday, September 19, 2006

Ok I think I got generic inheritance down.  I have a new question.

Do I need to override all non-public members of BusinessBase<T>?  This way I expose them at the level that I will actually be using them?

skagen00 replied on Tuesday, September 19, 2006

That would kind of defeat the purpose of inheritance, wouldn't it? ;)

I'm not sure what you mean by your question, perhaps you could rephrase it?

DeHaynes replied on Tuesday, September 19, 2006

   Yea, I thought about it after I typed it.  It didn't make sense. 

I guess what I am asking, is after I abstract BusinessBase<T>  to my class,

public abstract class ANBOBusinessBase<T> : Csla.BusinessBase<T> where T : ANBOBusinessBase<T>

is there any code in it that I need to bring up to my class level to expose it?  There is some custom stuff I want to do but if there wasn't and my only objective was to abstract the CSLA framework into my own namespace and thus allow my code to be upgraded with future versions of the CSLA framework, then my subclass could basically consist of

[Serializable()]
public abstract class ANBOBusinessBase<T> : Csla.BusinessBase<T> where T : ANBOBusinessBase<T>
{ }

Is that right?

skagen00 replied on Tuesday, September 19, 2006

That's pretty much it, yep!

 

RockfordLhotka replied on Tuesday, September 19, 2006

You should only override methods you want to change/enhance/replace. So yes, in the most basic sense you'd simply create an empty class - thus enabling future changes.
 
Rocky
 

is there any code in it that I need to bring up to my class level to expose it?  There is some custom stuff I want to do but if there wasn't and my only objective was to abstract the CSLA framework into my own namespace and thus allow my code to be upgraded with future versions of the CSLA framework, then my subclass could basically consist of

[Serializable()]
public abstract class ANBOBusinessBase<T> : Csla.BusinessBase<T> where T : ANBOBusinessBase<T>
{ }

Is that right?

DeHaynes replied on Tuesday, September 19, 2006

Thanks skagen and Rocky.  I know that teaching generics isn't part of your responsibilities, so I wanted to say that I really appreciate all the help.

DeHaynes replied on Tuesday, September 19, 2006

I saw in another post where Rocky said that you should only subclass the following classes.

  BusinessBase<T>
  BusinessListBase<T,C>
  CommandBase
  ReadOnlyBase<T>
  ReadOnlyListBase<T,C>
  NameValueListBase<K,V>

 

What about

EditableRootListBase<T>
SortedBindingList<T>
SmartDate
FilteredBindingList<T>

 

RockfordLhotka replied on Tuesday, September 19, 2006

DeHaynes:

What about

EditableRootListBase<T>
SortedBindingList<T>
SmartDate
FilteredBindingList<T>



In version 2.1 you should also subclass EditableRootListBase, yes.

The others are not base classes. You don't typically subclass them to do anything in a normal application, so creating a subclassed version of them has less value. It would be somewhat like subclassing String in case you wanted to enhance it someday.

Copyright (c) Marimer LLC