I have finally hit a problem I could not understand after searching the forum.
The call to
GetFrame(1).GetMethod.Name.Substring(4)
in PropertyHasChanged in BusinessBase is throwing an exception, sometimes. Using some traces, I found that the method name being returned is "ADD". This is the method in a EditableCollection that is creating a new object and adding that new object to its collection.
The ADD method code is:
Public Overloads Function Add(ByVal arLedger As String, _Setting APLedger works fine. Setting Customer fails with the exception. Both properties use PropertyHasChanged().
My Trace showed that when setting APLedger, the GetFrame(1).GetMethod call returned set_APLedger, as expected. But when setting Customer, ADD was returned.
I get this error whenever I run a production installed version of the program. In VS2005, I can only duplicate when running the Release config with Ctrl+F5. Any other combination works fine.
I am using CSLA 2.0 and VS2005
The application is a Windows app. This process that executes this code runs on a background thread via a BackgroundWorker.
I can work around this by changing the business object to use PropertyHasChanged("PropertyName") instead of just PropertyHasChanged, but I am REAL curious about WHY this is happening. Especially when it works for one property and not another.
Any insight would be appreciated.
I have attached a small txt file with the trace info that shows the method names being returned and the excption info.
Do your get and set blocks have the required compiler attribute to prevent inlining?
I'm guessing not, because it sounds like your properties have been inlined by the JIT compiler, so they really are running directly in the add method.
That's it. I have changed the properties.
I am distressed that my searches prior to my post did not enlighten me. After Rocky's reply, I sure found plenty.
Thanks
I also had the same problem... with an "add" method. And although I understand the solution for the problem (either add the no inlining attribute or specify the property) isn't it a good practice to verify the length of the string before calling substring?
So in the BusinessBase we should have (for example):
[System.Runtime.CompilerServices.MethodImpl( System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]}
instead of:
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
protected void PropertyHasChanged()
{
string propertyName = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name.Substring(4);
PropertyHasChanged(propertyName);
}
Am i totally off base? If so, please help me understand :)
Rick
I’ll add this to the wish list, though it is worth considering
that the “correct” solution is a string comparison to ensure the
text starts with “get_” or “set_” and throwing an
exception if not. String compares are not the cheapest thing in the world, so
you could debate whether this check is worth the expense to catch such an edge
case (which is why it isn’t there now).
But I’ll consider the idea for some future version anyway.
Maybe make it only active in debug mode and have it compile out of release mode
or something.
Rocky
From: ajj3085
[mailto:cslanet@lhotka.net]
Sent: Friday, October 26, 2007 2:30 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] Exception in PropertyHasChanged() in
BusinessBase
Well you're technically right, it won't solve any
issues. If you don't add the attribute and don't specify the property
name (which is the only time this blows up), then PropertyHasChanged will
return the METHOD being executed, not the PROPERTY just changed.
Obviously this isn't the desired result.
I guess an argument can be made that the exception should be caught and a more
meaningful one thrown. Certainly that might be a very good idea, because
it would quickly point out the issue, instead of people coming to the forum
searching for this same solution. ">
ajj3085:How expensive is the string compare vs. the reflection already used in the call to walk the stack trace?
Oh, it is quite incidental.
Defensive programming is a wonderful thing. But you can carry it too far, in my view anyway. If you stop and think about everything that could go wrong with every method you call, and wrap that method call with checks for every possibility, your code would be insane. Very defensive, but insane.
I totally agree with defensive programming where the likelihood of a bad thing happening is high, or where the consequences of a bad thing happening has a high cost.
But to take the time, and incur the overhead, of checking for every edge case - even those with little probablility of occurance and/or a (relatively) low cost when something happens - seems like a bit much to me.
Copyright (c) Marimer LLC