CSLA General: BusinessBase - Best Practise

CSLA General: BusinessBase - Best Practise

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


cjherasmus posted on Monday, September 17, 2007

I have a question regarding best practices in CSLA.

I have a base class from which I derive three subclasses. For example, my base class is Vehicle, my subclasses which derive from Vehicle are: Aeroplane, Car and Bicycle.

Should Vehicle derive from BusinessBase, or should each of the subclasses derive from BusinessBase?

Vehichle shouldn't be accessible from the application layer.

Thanks

Regards,

skagen00 replied on Monday, September 17, 2007

If you have enough behavior within your vehicle class to justify its existance, then yes - have your Aeroplane, Car, and Bicycle derive from Vehicle. If all you have is some common data fields you should seriously consider just having an interface on the three classes - called IVehicle - at which point the three classes should derive from BusinessBase.

*Regardless* of whether you have the vehicle base class or not, you'll want to have an interface IVehicle which exposes the common properties and methods - if Vehicle is a base class for the three, I would tend to have IVehicle be declared on Vehicle (which should be abstract) - if some things aren't implementable in Vehicle they would be abstract.

You'll find this interface is necessary, because you can't just pass around a variable typed to Vehicle<T>. You *can* pass around a variable typed to IVehicle.

Under really no circumstance does it seem to make sense to have Vehicle as a class and have the three subclasses derive from BusinessBase. (Under certain circumstances you might find that you want a vehicle that *doesn't* share any implementation with the vehicle base class, under which case I suppose you could declare other classes that implement IVehicle that derive from BusinessBase.

When it comes to CSLA classes especially, IMO, any concept of subclassing (if you want to leverage polymorphism) really must be reinforced with interfaces.

Good luck,

Chris

 

Troncho replied on Thursday, January 19, 2012

Hi everybody. I have one question regarding this post. I'm using CSLA 3.8

Let say I have a business base class called Person

public class Person : BusinessBase<Person>

{

private static PropertyInfo<Guid> PersonIdProperty = RegisterProperty<Guid>(c => c.PersonId);
public Guid PersonId
{
	get { return GetProperty(PersonIdProperty); }
	private set { LoadProperty(PersonIdProperty, value); }
}
 
private static PropertyInfo<string> NameProperty = RegisterProperty<string>(c => c.Name);
public string Name
{
	get { return GetProperty(NameProperty); }
	set { SetProperty(NameProperty, value); }
}
protected internal Person() { }

And from Person I derive Customer

public class Customer : Person

{

private static PropertyInfo<string> AliasProperty = RegisterProperty<string>(c => c.Alias);
public string Alias
{
	get { return GetProperty(AliasProperty); }
	set { SetProperty(AliasProperty, value); }
}

}

When I try to compile, I get these errors:

Error 2 Cannot convert lambda expression to type 'Csla.PropertyInfo<string>' because it is not a delegate type D:\Proyectos\NRG Global\NrgNet\Solution\Library.Base\... 17 80 Library.Base

Error 3 'NrgNet.Library.Base.GenPersonaBase' does not contain a definition for 'Alias' and no extension method 'Alias' accepting a first argument of type 'NrgNet.Library.Base.GenPersonaBase' could be found (are you missing a using directive or an assembly reference?) D:\Proyectos\NRG Global\NrgNet\Solution\Library.Base\... 17 87 Library.Base

Should I directly go with the interfase design and replace the inheritance structure as you suggested, or do you have any alternatives here?

Thanks in advance,

Troncho

JonnyBee replied on Thursday, January 19, 2012

You must understand generics better.
I recommend this MSDN Magazine artticle: Introducing Generics: http://msdn.microsoft.com/en-us/magazine/cc163683.aspx

You can only do inheritance like this:

  [Serializable]
  public class Vehicle<T> : BusinessBase<T>, IVehicle where T : Vehicle<T>
  {
      // add common properties 
  }
 
  [Serializable]
  public class Car : Vehicle<Car>
  {
    
  }

  [Serializable]
  public class Plane : Vehicle<Plane>
  {
    
  }

Troncho replied on Thursday, January 19, 2012

Thanks for the advice Jonny! I'll go through the MSDN article you mention and then come back to this topic :)

Troncho replied on Friday, January 20, 2012

Ok, I've gone through Generics for 2 days now. I've re read all I found around regarding generics.

Still one definition blows my mind about the way generics are being used here:

class BusinessBase<T> : BusinessBase ... where T : BusinessBase<T>

When I try to read this statement in my mind I get an infinite recursive loop over T, as when trying to constrain T, I go back to BusinessBase<T>

Same goes for the class Vehicle<T> : BusinessBase<T> where T : Vehicle<T>

When I try "reading" it in my mind, I still get the same infinite recursive loop over T.

Jonny, what am I missing? What am I reading wrong?

Thanks in advance :)

JonnyBee replied on Saturday, January 21, 2012

It's a generic constraint and the Type specifier for all use of T inside your class.

Take for example:

    public virtual T Save()

You will usually want to get the correct type back from a Save, right?
And you cannot create an instance of Vechicle<T> because you do not have a constraint!!
But inside your class you can access methods and properties on that type on variables declared as T.

So take the class

public class Car : Vehicle<Car>

T is here Car and the Save method will return an object of type Car.

Troncho replied on Saturday, January 21, 2012

Hey, Jonny, thanks again for clarifying Big Smile

As a matter of fact, I was having a real syntax problem on the "where T : Vehicle<T>" part.

Then, I came across with this web reference: http://www.somethingorothersoft.com/2010/09/27/crtp-in-c/

It's about Reflexive type parameter constraints. And then I understood the whole picture!

 What the constraint really says is that T is a class that derives from Vehicle, which is what Car is.

Thank you very much.

The actual solution I'm building is upon <Persons> and their different appearences on a Business Solution.

A Person doesn't need to be instanciated.

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

What I need instances of are all these classes, for example:

public class Customer : Person<Customer>

public class User : Person<User>

public class Vendor : Person<Vendor>

public class Employee : Person<Employee>

etc...

Now, here is an extra question regarding this topic:  What would you include in an IPerson interface, regarding this entity hierarchy I'm defining, and considering it's deriving the whole thing from BusinessBase<T>

Thanks again Jonny...

JonnyBee replied on Saturday, January 21, 2012

Hi,

The IPerson interface should define common properties and methods (typically implemented in Person<T>) and is the only way that you can "cast" the Customer/User/Vendor etc into a generic/common class and access the properties/methods.

You may also create more than one Interface if that is more suitable (f.ex properties vs behavior).  You can also add the one or more interface to subclasses when you declare them.

 

Troncho replied on Saturday, January 21, 2012

Ok, I see. I'll do some Interface coding and come back to you with the results. Thanks and have a nice weekend.

Copyright (c) Marimer LLC