Some while ago, I followed Rocky's advice and exposed my SmartDate (SmartInt16, SmartInt32, etc) variables as strings instead of SmartDates (and so on).
However, I just got bit while using the MinValue<T> rule.
public static bool MinValue<T>(object target, RuleArgs e) where T : IComparable // Code barfs on the next line!
T value = (T)pi.GetValue(target,
T min = (T)args[
"MinValue"]; int result = value.CompareTo(min); Here's the problem. When T gets passed in, it gets passed in as, let's say, an Int32.However, the property isn't an Int32, it's a String! So, the cast to T into the value variable fails.
Anyone else hit this snag, and what was your solution?
I was looking at the whole issue of SmartXXX's for the future. I have one question: why is it necessary when we now have nullables (accepted that if you are on .Net 1.1 it is the only way)
Simon
simon_may:I was looking at the whole issue of SmartXXX's for the future. I have one question: why is it necessary when we now have nullables (accepted that if you are on .Net 1.1 it is the only way)
Simon
I dunno. I haven't tried incorporating them.
simon_may:I was looking at the whole issue of SmartXXX's for the future. I have one question: why is it necessary when we now have nullables (accepted that if you are on .Net 1.1 it is the only way)
There are a couple of issues with nullable types:
1. Many UI controls do not deal well (or at all) with the concept of a null value. SmartDate (and the other smart controls) convert nulls to empty strings, or other suitable representations, for UI controls. Yes, many of the third-party libraries have nullable support built in, but many of the built-in controls still don't.
(And don't ask why, because I don't know why, and it sure seems like an obvious thing that MS overlooked... )
2. Nullable types do not translate null values to a DBNull value for databases (and there is a difference). SmartDate has that functionality built in. Also something that seems rather obvious, since it would seem that the main impetus for nullable types is to work well with databases...
Thanks TMG. You have saved me a lot of heartache. Typical of M$ provide a really good feature with a dirty great flaw in it. As I do a lot of code gen I can get around the probs.
Simon
simon_may:Thanks TMG. You have saved me a lot of heartache. Typical of M$ provide a really good feature with a dirty great flaw in it. As I do a lot of code gen I can get around the probs.
Simon
I will say that I have done little research to date on .NET 3.5, so it's possible that they've addressed this. And I would hope that WPF - something else I haven't looked at much - deals with nullable binding better than WinForms. I'd also be curious to know how LINQ manages this.
I can understand MS's "90% approach" to their UI controls - that's the one area where they really flex their IP muscle, and why give away all the really cool stuff? But the missing functionality in the nullable types seems rather egregious to me. MSDN says the best use for nullable types is to "represent things that exist or do not exist depending on the circumstance" - and then goes on to talk about "a nullable column of a database table [that] might exist in one row of the table but not another." Honestly, that statement makes no sense to me, though it seems to shed a little light on why nullable types work the way they do (and further shows that MS wasn't thinking too much about the problem they were trying to solve.) Lastly, while the "ToString()" implementation of nullable types returns an empty string if the variable has no value, that's not very helpful in most circumstances.
- Scott
TMG, Thanks for the info. Seems that the guy form M$ has never written a business app otherwise he might talk some sense rather a party line that makes no sense in the real world.
Simon
SmartDate is not intended to solve the null problem. It is
intended to solve the empty problem. There’s a difference.
·
A null value indicates a value not yet supplied.
·
A non-null value indicates a value that has been supplied –
which might be an actual value or an empty value.
·
An empty value is a supplied value, that is empty. It could be
infinitely small or large relative to other values.
Null and Empty are not the same thing – we just often use
the “null” concept to represent Empty because there is no Empty
concept available.
Look at SQL – no way to indicate an Empty date value other
than either using null or picking some arbitrary real date to be the empty
placeholder. Yet the idea of an empty date is central to a lot of applications.
Fortunately, very few applications actually need the null concept at all, so it
is fine to use null as a placeholder for Empty.
But if you are writing one of those few apps where null actually
matters, then you are in a spot…
This null thing is one of my pet peeves though. People misuse it
all the time. Null exists to support the idea that a user hasn’t supplied
a value – so null <> “” and null <> 0 and null
<> false. The “”, 0 and false values are actual values, which
implies they were supplied by the user. Null is used to indicate something not
supplied (yet anyway).
(I’m ignoring the foreign key use of null in a database,
because that’s a concept unto itself and is separate from the use of null
in value columns/properties)
Very few apps actually have this business requirement. Those apps
that do have this requirement must, by definition, have some UI representation
so the user knows whether a value has been supplied or not. With numerics this
is relatively easy – 0 is visibly different from “”, so you
can use “” to represent null. But for strings it is hard, because there’s
no clear way to represent a null in a textbox. So you probably need an
associated checkbox control, or a specialized textbox that can show text like “<null>”
in italics or something to denote a non-supplied value.
The same is true for a date if you want the user to type it in
as freeform text. Again, the “” can be Empty, but then it can’t
be null. So you have the same problem as with regular text.
Boolean isn’t too bad if you have a tri-state checkbox.
That way you can show true/false/unknown and have unknown be proxy for null.
Rocky
From: ajj3085
[mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 1:38 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Problem with MinValue<T> and
MaxValue<T>!
3. It allows you to sort all "null" values
as minimums or maximums, depending on the EmptyIsMax value. So maybe in
one case your empty SmartDate should appear first in ascending order, but in
another case, it should appear at the end of the list.
Yo! Everybody!
Y'all can start all the threads you want, but could we keep this one on track?
I'm not able to switch to v3.5 just yet.
So I'm looking for a v2 solution to the immediate problem I posed...
Thanks!!!!!!!
The CoerceValue() code should back-port, that’s why I
brought it up.
Rocky
From: david.wendelken
[mailto:cslanet@lhotka.net]
Sent: Tuesday, January 29, 2008 2:14 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] RE: Problem with MinValue<T> and
MaxValue<T>!
Yo! Everybody! ">
Y'all can start all the threads you want, but could we keep this one on
track?
I'm not able to switch to v3.5 just yet. ">
So I'm looking for a v2 solution to the immediate problem I posed...
Thanks!!!!!!!
David,
I think since you control both ends of this that you just have to line them up correctly.
You said T gets "passed in" as an Integer.
That means your declaration is something like this:
ValidationRules.AddRule(AddressOf MinValue(Of Integer), New MinValueRuleArgs(Of Integer)("Price", 0))Why not change it to:
ValidationRules.AddRule(AddressOf MinValue(Of String), New MinValueRuleArgs(Of String)("Price", 0))
Joe
JoeFallon1:David,
I think since you control both ends of this that you just have to line them up correctly.
You said T gets "passed in" as an Integer.
That means your declaration is something like this:
ValidationRules.AddRule(AddressOf MinValue(Of Integer), New MinValueRuleArgs(Of Integer)("Price", 0))Why not change it to:
ValidationRules.AddRule(AddressOf MinValue(Of String), New MinValueRuleArgs(Of String)("Price", 0))
Joe
Because if I evaluate it as a string, 11 is less than 2. :)
david.wendelken:Some while ago, I followed Rocky's advice and exposed my SmartDate (SmartInt16, SmartInt32, etc) variables as strings instead of SmartDates (and so on).
However, I just got bit while using the MinValue<T> rule.
public static bool MinValue<T>(object target, RuleArgs e) where T : IComparable
{
DecoratedRuleArgs args = (DecoratedRuleArgs)e;
PropertyInfo pi = target.GetType().GetProperty(e.PropertyName);// Code barfs on the next line!
T value = (T)pi.GetValue(target, null);T min = (T)args["MinValue"];
int result = value.CompareTo(min);
Here's the problem. When T gets passed in, it gets passed in as, let's say, an Int32.However, the property isn't an Int32, it's a String! So, the cast to T into the value variable fails.
Anyone else hit this snag, and what was your solution?
What about using Convert.ChangeType()? It returns an Object, but it should be a castable object at that point...
- Scott
tmg4340:What about using Convert.ChangeType()? It returns an Object, but it should be a castable object at that point...
That's an incredibly good idea!
// dataType is a new parameter I introduced so I could know type T is. I would love to not use it! Type t = Type.GetType(dataType);T value = (T)
Convert.ChangeType(pi.GetValue(target, null), t);T min = (T)
Convert.ChangeType(args["minValue"],t);The above code works, provided I supply the dataType parameter with the correct class name.
I would prefer to have it smart enough to just use T, but I haven't figured out the syntax...
Can't figure out the syntax to ask a static method what T is, either, which would be another way to do this without an extra dataType parameter.
Ideas?
I wasn't really following this thread, so I don't know the exact issue. But if you are trying to coerce a value to a different type, that's tricky due to the various edge cases.
I spent a lot of time for CSLA 3.5 addressing this issue, culminating in the CoerceValue() methods in the Csla.Utilities class. I don't know that it solves every case, but it solves all the test cases I threw at it, and the ones that were provided by people struggling with coercion in DataMapper.
RockfordLhotka:I wasn't really following this thread, so I don't know the exact issue. But if you are trying to coerce a value to a different type, that's tricky due to the various edge cases.
I spent a lot of time for CSLA 3.5 addressing this issue, culminating in the CoerceValue() methods in the Csla.Utilities class. I don't know that it solves every case, but it solves all the test cases I threw at it, and the ones that were provided by people struggling with coercion in DataMapper.
I should also point out that SmartDate in 3.5 now has a whole lot of type coercion functionality of its own - including a set of cast operators and a TypeConverter implementation. CoerceValue() relies on your type implementing some/all of that infrastructure to work, so if you are using your own custom SmartXYZ types, they will probably need to have similar operators and a TypeConverter (at least for conversion to/from string).
david.wendelken:tmg4340:What about using Convert.ChangeType()? It returns an Object, but it should be a castable object at that point...
That's an incredibly good idea!
// dataType is a new parameter I introduced so I could know type T is. I would love to not use it!
Type t = Type.GetType(dataType);
T value = (T)Convert.ChangeType(pi.GetValue(target, null), t);
T min = (T)Convert.ChangeType(args["minValue"],t);
The above code works, provided I supply the dataType parameter with the correct class name.
I would prefer to have it smart enough to just use T, but I haven't figured out the syntax...
Can't figure out the syntax to ask a static method what T is, either, which would be another way to do this without an extra dataType parameter.
Ideas?
I will say one other thing - the Convert class expects that the value in question implements IConvertible. So you might want to make a modified version of MinValue<T> to include the IConvertible requirement, in addition to IComparable. That will help you catch problems at compile-time.
As for your other question - can you just use "T.GetType()"? Given no other hints, generic placeholders always equate to an Object. Or you could try "typeof(T)" as well.
- Scott
tmg4340:I will say one other thing - the Convert class expects that the value in question implements IConvertible. So you might want to make a modified version of MinValue<T> to include the IConvertible requirement, in addition to IComparable. That will help you catch problems at compile-time.
Thanks! I'll look into it.
As for your other question - can you just use "T.GetType()"? Given no other hints, generic placeholders always equate to an Object. Or you could try "typeof(T)" as well.
I feel like SUCH a goober. I REALLY thought I had tried typeof(T) and it wouldn't compile. But it works great. Need vacation. Bad.
I'm pretty sure T.GetType() won't work.
david.wendelken:I feel like SUCH a goober. I REALLY thought I had tried typeof(T) and it wouldn't compile. But it works great. Need vacation. Bad.I'm pretty sure T.GetType() won't work.
I know how you feel - I haven't had a "real" vacation in a couple of years.
(It's funny - that's about how old my son is... )
I started my .NET life as a VB.NET programmer, and even after more than a year of C# programming, I still can't get it straight in my head when to use "typeof" and when to use "GetType" in these instances...
- Scott
Copyright (c) Marimer LLC