Generic CSLA Factory methods...

Generic CSLA Factory methods...

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


geordiepaul posted on Thursday, August 24, 2006

I'm still having trouble getting my head round Generics particularly when using the CSLA, I could remove the generic element from structure altogether but I don't want to lose the strong typing that the CSLA provides through the Save() method etc.

I have an abstract base class...

public abstract class AbstractBase<T> : BusinessBase<T> where T : Base<T>

There is a chain of inheritance that looks like this

Now since I don't know the type of object until I hit a database I have created an object factory which is basically a CommandBase object that hits the DB determines the type object and passes the datareader to the relevant concrete class which then creates the object. These object can all be maniulated as type AbstractBase so the concrete type doesn't really matter

The factory returns the item of type object since I could return it as type AbstractBase<T> since I didn't know the type T until the factory has done it's work

Ideally I would have been a static method on AbstractBase like...

public static AbstractBase<T> GetAbstractBase(int Id)
{
   AbstractFactory factory;
   factory = DataPortal.Execute<AbstractFactory >(new AbstractFactory(Id));

   return (AbstractBase<T>)factory.ConcreteObject;
}

but again I wouldn't know the value of T so wouldn't be able to call the method. So I could have the Factory itself return the object but I can't convert it to AbstractBase because I don't know T. Well I do really becuase I can get the type of objct returned by the factory but this won't compile..

AbstractFactory factory;
factory = DataPortal.Execute<AbstractFactory >(new AbstractFactory(Id));

return
(AbstractBase<factory.ConcreteObject.GetType()>)factory.ConcreteObject;

Surely there is a better way of doing this I just don't know what it is! Can anyone assist?


 

 

xal replied on Thursday, August 24, 2006

There's really no way of having strong typing that way. You could make the object implement an interface, and return that. But that way the problem is not really solved, you'll have to probe for the actual type.

The question is: How do you get to load this data? Usually you will have a readonly list that contains info about the object you're going to retrieve. The user picks something from that list and you retrieve the bo based on that ID. In that scenario, why not also include information about the type? That way, you can know the type before loading, and you could call the appropiate methods. Your readonly object could even abstract those calls for you, but you will definitely need to do some conditional evaluation to match either the method you're going to call or the type of the object that was returned.

What's important is to realise that it is not a problem that relates to generics at all...
Try to do the same thing without generics. What would be the type returned by your factory? Again: an interface or Object.
Generics provide type safety at compile time, and what you're trying to accomplish takes place at runtime.


Andrés

geordiepaul replied on Thursday, August 24, 2006

Thanks for the reply

Without generics it become easy I could just say

ObjectBase object = ObjectFactory.GetObject(id);

I don't need to know anything about ObjectBase before making the call whereas the Generic method would have to be

ObjectBase<T> object = ObjectFactory.GetObject(id);

At which point I don't know the type of T. This essentially means that what I'm trying to achieve won't work. Since the caller doesn't need to know T and I don't really want them to if they need to convert to the concrete type then that was up to the caller.

I would like to avoid having pass the type into the method/factory as this would over complicate the method call and would require type knowledge and I won't always necessarily be creating the object from like you say a readonly list.

xal replied on Thursday, August 24, 2006

If that is all you want, then again, go with the interface approach:

IObjectBase object = ObjectFactory.GetObject(id);

What you want to do involves polimorphism and generics are not polimorphic. Implementing an interface is the only way around that.

The reason is simple, suppose you have a class like:

public class MyClass<T>
{
void DoSomething<T>(T value) {...}
}

If you pass different types to T, the method signature will not be the same. So, two objects that have different types for T will have different interfaces.



Andrés

geordiepaul replied on Thursday, August 24, 2006

I had thought about the Interface approach but then dismissed it for some reason but what you've said makes sense.

Thanks for that.

xal replied on Thursday, August 24, 2006

I <think> that in c# you can right click on a class and select "Extract interface". That way the interface is created automatically and you'll save a couple of minutes. Again, I <think>, but I'm not certain.


Andrés

ajj3085 replied on Thursday, August 24, 2006

You'd be correct.  Its as simple as that.

geordiepaul replied on Thursday, August 24, 2006

Yeah unfortunately it doesn't take any methods from the base class (such as BusinessBase.Save()) but it's not a massive job to add them in.

Cheers for your advice on this.....and interface has proven successful :-)

ajj3085 replied on Thursday, August 24, 2006

Why would you want methods from the BusinessBase class?

At any rate, interfaces can inherit other interfaces.. just declare it to inherit Core.IEditiableBusinessObject, and possibly ISavable (I think... but that's only if you're using 2.1 beta).

HTH
Andy

geordiepaul replied on Friday, August 25, 2006

I want access to Save() through the interface but I'm not quite sure yet.

ajj3085 replied on Friday, August 25, 2006

Well if you declare your interface like this:

public interface IMyInterface : Csla.Core.ISavable {
// Interface defintion here
}

Then you can access Save via your IMyInterface.

Copyright (c) Marimer LLC