Exception in PropertyHasChanged() in BusinessBase

Exception in PropertyHasChanged() in BusinessBase

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


JimStone posted on Wednesday, August 01, 2007

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, _
                                                         ByVal customer As String, _
                                                        
ByVal apLedger As String, _
                                                        
ByVal bypassImport As Boolean) _
                                                       
As ARReference

Dim item As ARReference = AddNew()
item.APLedger = apLedger
item.Customer = customer
item.ARLedger = arLedger
item.BypassImport = bypassImport
EndNew(Count)
Return item

End Function

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.

RockfordLhotka replied on Wednesday, August 01, 2007

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.

JimStone replied on Wednesday, August 01, 2007

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

RickMartinez replied on Friday, October 26, 2007

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)]
protected void PropertyHasChanged()
{
   
 string propertyName = new System.Diagnostics.StackTrace().GetFrame(1).GetMethod().Name;

     if
  (propertyName.Length >= 4)

             propertyName = propertyName.Substring(4);

      PropertyHasChanged(propertyName);

}

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

ajj3085 replied on Friday, October 26, 2007

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.  Smile [:)]

RockfordLhotka replied on Friday, October 26, 2007

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.  Smile <img src=">


ajj3085 replied on Friday, October 26, 2007

How expensive is the string compare vs. the reflection already used in the call to walk the stack trace? 

RockfordLhotka replied on Friday, October 26, 2007

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.

JustinJones replied on Wednesday, August 01, 2007

This attribute:

[MethodImpl(MethodImplOptions.NoInlining)]

I prefer the named version (
PropertyHasChanged("PropertyName")) because it doesn't have to get a call stack. 

Copyright (c) Marimer LLC