Why didn't Rocky implement ISavable on the BusinessBase class? I can understand that he wanted BusinessBase<T> to return a type-specific object when saving (<T> Save()), but then why not place the functionality in BusinessBase and call the base implementation in BusinessBase<T>?
The ISavable implementation requires the Save() method.
If I move the Save() method to Core.BusinessBase then it must return type object.
At that point BusinessBase<T> can't override Save() to return a T, because an override can't vary by only the return type.
If I do down that route, then there's no value in having BusinessBase<T> at all really, because the point of that class is to get Save() to return a T.
I thought about that too.
But Save() is virtual. If I move the REAL save behaviors up to
Core.BusinessBase you can bet good money that people who don’t use
BusinessBase<T> would want this new method to be virtual for the same
reasons.
But I can’t make Save() NOT virtual without breaking much
(most?) existing code.
So I’m left making BOTH methods virtual. Then there’s
a documentation question: which do I override, and when? The resulting chaos is
something I don’t think is a good thing.
Rocky
From: xal
[mailto:cslanet@lhotka.net]
Sent: Thursday, February 22, 2007 1:15 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] ISavable not implemented on BusinessBase
Well, correct me if I'm wrong but arguably, you could
implement ISavable in BusinessBase with another name, like SaveObject (maybe
even make it private/protected if you prefer...).
That way, BusinessBase<T> can implement Save returning the correct type
and you don't break compatibility...
Andrés
Another way to look at this (though it may not be popular), is that inheriting from Csla.Core.<anything> is an advanced concept. I put the things into a sub-namespace because they aren't really intended for daily use. If you are inheriting from them, it is because you are doing something out of the ordinary (at least from a CSLA perspective). So if you have to do some extra work (like implement ISavable in your own base class), I'm not sure that's a terrible thing.
Please note that I have no problem with people using the stuff in Csla.Core! That's just fine to do - but it is an advanced scenario and may require extra work and understanding.
Well, it seems to me that with all this said, the real solution is for microsoft to fix visual studio to work with generic forms...???
I have not yet found a solution to the generic form problem that presents itself well (or at all).
Thinking about the purpose of the <T>Save() method a little more, however... The save method is the only method that returns a specific type. It seems to me that there is a lot of extra work having to be done in order to keep Save() type-specific/generic. I noticed that BusinessBase has the Clone method that does not return type-specific/generic, what is so special about the Save() method?
I could be very wrong... But it seems to me that the BusinessBase.Save() method could be something more like "protected virtual object BusinessBase.SaveObject()" and "<T> BusinessBase<T>.Save()" could cast the object for you and even though the generic form of Save() wouldn't be overridable, you would still be able to modify the functionality of saving by overriding BusinessBase.SaveObject(). Seems like this could be done to the clone method, as well?
BusinessBase:
protected virtual object SaveObject();
protected virtual object CloneObject();
BusinessBase<T>:
public <T> Save() { return (T) base.SaveObject(); }
public <T> Clone() { return (T) base.CloneObject(); }
Thank you...
First off, I've looked at your posts before, and though it is a good solution, my project is a C# project and I haven't found a C# port of your MagikAttribute class. If you have one, let me know, PLEASE ;)
Secondly, this question (pertaining to the placement of the save method), for me, is more of a question in the foundation of the CSLA framework and how "people" think it "should be." Not to doubt rocky's framework - it's the best I've seen - but I just want to know if it this is really the best way to deal with this (for I don't think it is).
Rocky,
I understand what your saying about not making a change without a good reason, and I hate to beat a dead horse, but this seems to me as though it IS a good reason; Normalizing the purpose of the generic form of BusinessBase and the way cloning and saving works. Further-more, I don't believe the change I suggested would cause existing applications to break...
Technically no, it wouldn’t break existing code.
However, as I discussed in an earlier post, BOTH SaveObject()
and Save() would need to be virtual to avoid this being a breaking change –
and that would be just as bad a design flaw as the current one as I see it.
Which method do you override? The obvious one is Save(), but the RIGHT one
would actually be SaveObject()…
You must remember that I’m a one-man support team here.
Not only do I do the dev work, but I have to field all the questions about the
quirks (like this one). So I’m very careful (where possible) to minimize
the quirks so as to minimize the time I spend answering questions about them,
when I could be doing fun stuff like adding features or spending time with my
kids J
What I’ll do, is add this to the wish
list as a possible future enhancement/change. But as you can tell, I’ve
gotten this into a spot where there are no good answers and ultimately I need to
choose the lesser of two evils…
Rocky
Rocky,
Well spoken and received. Thanks for the time you've spent on the thought thus far.
To answer of how it should be, there’s no doubt
that ISavable would be better implemented in Core.BusinessBase. If I didn’t
have to worry about backward compatibility, I’d have certainly put it
there. But the cost to doing that was, imo, too high and so this was a
necessary compromise.
This is the way with frameworks btw. Your version 1.0 can be
anything you want. But everything after that point is compromise. Finding a
balance between the “right” solution and the “practical”
solution.
Every now and then you get “lucky”, and there’s
a major tech change that externally breaks things (like COM to .NET), and you
have the chance to fix those compromises – kind of a reset to 1.0 again.
But at that point the cycle of compromise just resumes…
If you really get down to it, I’m not entirely sure
I’d have used generics in the base classes at all. Having strongly typed
Save() and Clone() methods is probably not actually worth the cost of using
generics.
Of course then market perception enters into it. If CSLA .NET
2.0 hadn’t very visibly use generics it is quite likely that people would
have viewed it as irrelevant from day one. If you don’t use the shiny new
toys you must have missed the point after all.
In retrospect though, these particular toys, while very shiny,
also have some very sharp spines.
Rocky
Andréa,
If you don't mind briefly explaining to me: Based on what you said previously, I don't understand why generic forms are such a problem. It was my impression that due to generics, the designer couldn't instantiate an instance of the form because it doesn't know what type to pass to the class. Is this even remoting close to the truth?
The name... Sorry! I have a friend named Andréa, so Im guessing I overlooked it subconciously thinking it was his name I was seeing. ;)
Anyways, I look forward to seeing your newest version of the fix.
Yes, if I was willing to break most existing objects in the
hundreds or thousands of apps built on CSLA .NET I could easily make some
changes that would work.
But IF I made such a change it would have to be for a very
compelling benefit, and it would have to be at a major version change for CSLA
itself – because that’s a non-trivial thing to consider.
Right now, the burden for creating your own non-generic subclass
of Core.BusinessBase is not high. While having to implement a simple interface is
not ideal, I can’t see how that one, relatively advanced and uncommon,
scenario could justify breaking everyone’s code.
Rocky
Copyright (c) Marimer LLC