SetProperty<bool> problem

SetProperty<bool> problem

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


Boris posted on Tuesday, March 11, 2008

This is my first post here. I've been using the CSLA framework for quite some time now.
Thank you Rocky, for putting in so much time and effort into developing this masterpiece! All your hard work is greatly appreciated!

I’m using 3.5 Beta 2 (3.5.0.080222) in my current project and I’m pretty happy with it.

Here is one unexpected (at least for me) behavior:

// Here comes the test
Patient patient = Patient.NewPatient();
Assert.AreEqual(patient.BoolField, false);
patient.BoolField = true;
Assert.AreEqual(patient.BoolField, true);


// This code will pass the test

private static PropertyInfo<bool> BoolFieldProperty =
    RegisterProperty<Boolean>(typeof(Patient),
    new PropertyInfo<bool>("BoolField", "Bool Field", false));

public bool BoolField
{
    get { return GetProperty<bool>(BoolFieldProperty); }
    set { SetProperty<bool>(BoolFieldProperty, value); }
}

// This code fails the test
private static PropertyInfo<bool> BoolFieldProperty =
    RegisterProperty<bool>(typeof(Patient),
    new PropertyInfo<bool>("BoolField", "Bool Field", false));

private bool _boolField = BoolFieldProperty.DefaultValue;
public bool BoolField
{
    get { return GetProperty<bool>(BoolFieldProperty, _boolField); }
    set { SetProperty<bool>(BoolFieldProperty, ref _boolField, value); }
}

I was kind of favoring the second approach, and according to the latest posts it should work...For child objects I do understand that the CSLA has to manage the fields, but this is not a child object.

So far I have encountered this behavior only for the Boolean type...
Let me know what you think and if it is a CSLA issue, or I got too much to drink last night ;)



xal replied on Tuesday, March 11, 2008

Something that caught my eye whas that in the code that DOES pass the test you have this (note the bold parts):

private static PropertyInfo<bool> BoolFieldProperty =
    RegisterProperty<Boolean>(typeof(Patient),
    new PropertyInfo<bool>("BoolField", "Bool Field", false));


I don't use C# as much as VB, but i believe both (bool and Boolean) are interchangeable, right?

Not that it's necessarily related to your problem, but just curious...

Andrés

RockfordLhotka replied on Wednesday, March 12, 2008

Which Assert fails the test, the first or second?

In other words, is it that the default isn't being set, or the changed value isn't being recorded?

Boris replied on Wednesday, March 12, 2008

Thank you xal and Rocky for responding!
Using Boolean vs bool is not the problem, I've tried both...

Rocky,

The very last Assert fails!
Assert.AreEqual(patient.BoolField, true);

What is interesting is that the previous line:
patient.BoolField = true;
will not thow an exception, but it will also Not change the value....

Thanks again, and have a nice day!!

Bob Matthew replied on Wednesday, March 12, 2008

I ran into this one too.  Specifically if the user code has it's own private backing field instead of a the CSLA-managed field, you're going to run into problems with the boolean values.

The following overload is the culprit:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, bool throwOnNoAccess)

It conflicts with the GetProperty you think that you're using:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)

Normally when you're working with strings or integers or decimals or whatever, you'll say:
return GetProperty<DateTime>(CreatedDateProperty, _createdDate)

and it will call the "P Field" overload.  But when you say:
return GetProperty<bool>(IsWhateverProperty, _isWhatever);

It's calling the "throwOnNoAccess" overload.  There are several ways around this problem.  One way is to create another method. let's call is "GetPropertyEx" and it would look like this:

protected P GetPropertyEx<P>(PropertyInfo<P> propertyInfo, P field)
{
   return GetProperty<P>(propertyInfo, field);
}

Effectively what this does is binds itself to the private-backing field overload rather that trying to determine which overload to use when a boolean value is present.

Another approach that I've seen is to "simulate" private backing fields through managed backing fields:
public DateTime CreatedDate
{
 get { return GetProperty<DateTime>(CreatedDateProperty); }
 set { SetProperty<DateTime>(CreatedDateProperty, value); }
}
private DateTime _createdDate
{
 get { return ReadProperty<DateTime>(CreatedDateProperty); }
 set { LoadProperty<DateTime>(CreatedDateProperty, value; }
}

In this manner, you're always working with CSLA-managed fields but you can access them in a way that is identical to private backing fields.  You could even compress the "private DateTime _createdDate" getter and setter to a single line.

Boris replied on Wednesday, March 12, 2008

Thank you Bob!
I went with the first approach - added the code below to the BusinessBase.cs:

    protected P GetBooleanProperty<P>(PropertyInfo<P> propertyInfo, P field)
    {
        return GetProperty<P>(propertyInfo, field);
    }

And used that version for every bool field...It worked!!
Maybe for the next release I don't need to that...

Cheers!!


Bob Matthew replied on Wednesday, March 12, 2008

Technically, you may want to have every property go through the "GetPropertyEx" method I suggested because then your code generation is the same for every property.

Boris replied on Thursday, March 13, 2008

O-o yes, you are right!
Thank you so much...

RockfordLhotka replied on Saturday, March 15, 2008

I just checked in a fix for this problem. The fix is to use an enum to specify whether to throw an exception when the user isn't authorized - thus avoiding any overload conflict with the bool type.

This fix will break beta 1&2 users that explicitly pass in the throwOnNoAccess parameter value. Sorry about that, but this was an important issue - the framework can't simply not work with properties of the bool data type!!

I did not change the old code for version 2.0-3.0 syntax, so all existing 3.0 code should continue to upgrade to 3.5 just fine in this regard.

Bob Matthew replied on Monday, March 17, 2008

You've got the bool issue fixed and it's working great in BusinessBase.cs, but throwOnNoAccess still occurs in the ReadOnlyBase.cs, line 653.

RockfordLhotka replied on Monday, March 17, 2008

Oh, missed that one, oops!

 

Thanks!

 

 

From: Bob Matthew [mailto:cslanet@lhotka.net]
Sent: Monday, March 17, 2008 1:07 PM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] SetProperty<bool> problem

 

You've got the bool issue fixed and it's working great in BusinessBase.cs, but throwOnNoAccess still occurs in the ReadOnlyBase.cs, line 653.



RockfordLhotka replied on Thursday, March 13, 2008

Well that is a good point – and an unexpected/unplanned side-effect. Grumble..

 

I need to think about this a bit – I may be willing to break older code to ensure the new syntax works properly – just gotta think it through.

 

Rocky

 

 

From: Bob Matthew [mailto:cslanet@lhotka.net]
Sent: Wednesday, March 12, 2008 11:07 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] SetProperty<bool> problem

 

I ran into this one too.  Specifically if the user code has it's own private backing field instead of a the CSLA-managed field, you're going to run into problems with the boolean values.

The following overload is the culprit:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, bool throwOnNoAccess)

It conflicts with the GetProperty you think that you're using:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)

Normally when you're working with strings or integers or decimals or whatever, you'll say:
return GetProperty<DateTime>(CreatedDateProperty, _createdDate)

and it will call the "P Field" overload.  But when you say:
return GetProperty<bool>(IsWhateverProperty, _isWhatever);

It's calling the "throwOnNoAccess" overload.  There are several ways around this problem.  One way is to create another method. let's call is "GetPropertyEx" and it would look like this:

protected P GetPropertyEx<P>(PropertyInfo<P> propertyInfo, P field)
{
   return GetProperty<P>(propertyInfo, field);
}

Effectively what this does is binds itself to the private-backing field overload rather that trying to determine which overload to use when a boolean value is present.

Another approach that I've seen is to "simulate" private backing fields through managed backing fields:
public DateTime CreatedDate
{
 get { return GetProperty<DateTime>(CreatedDateProperty); }
 set { SetProperty<DateTime>(CreatedDateProperty, value); }
}
private DateTime _createdDate
{
 get { return ReadProperty<DateTime>(CreatedDateProperty); }
 set { LoadProperty<DateTime>(CreatedDateProperty, value; }
}

In this manner, you're always working with CSLA-managed fields but you can access them in a way that is identical to private backing fields.  You could even compress the "private DateTime _createdDate" getter and setter to a single line.



RockfordLhotka replied on Thursday, March 13, 2008

Well that is a good point – and an unexpected/unplanned side-effect. Grumble..

 

I need to think about this a bit – I may be willing to break older code to ensure the new syntax works properly – just gotta think it through.

 

Rocky

 

 

From: Bob Matthew [mailto:cslanet@lhotka.net]
Sent: Wednesday, March 12, 2008 11:07 AM
To: rocky@lhotka.net
Subject: Re: [CSLA .NET] SetProperty<bool> problem

 

I ran into this one too.  Specifically if the user code has it's own private backing field instead of a the CSLA-managed field, you're going to run into problems with the boolean values.

The following overload is the culprit:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, bool throwOnNoAccess)

It conflicts with the GetProperty you think that you're using:
protected P GetProperty<P>(PropertyInfo<P> propertyInfo, P field)

Normally when you're working with strings or integers or decimals or whatever, you'll say:
return GetProperty<DateTime>(CreatedDateProperty, _createdDate)

and it will call the "P Field" overload.  But when you say:
return GetProperty<bool>(IsWhateverProperty, _isWhatever);

It's calling the "throwOnNoAccess" overload.  There are several ways around this problem.  One way is to create another method. let's call is "GetPropertyEx" and it would look like this:

protected P GetPropertyEx<P>(PropertyInfo<P> propertyInfo, P field)
{
   return GetProperty<P>(propertyInfo, field);
}

Effectively what this does is binds itself to the private-backing field overload rather that trying to determine which overload to use when a boolean value is present.

Another approach that I've seen is to "simulate" private backing fields through managed backing fields:
public DateTime CreatedDate
{
 get { return GetProperty<DateTime>(CreatedDateProperty); }
 set { SetProperty<DateTime>(CreatedDateProperty, value); }
}
private DateTime _createdDate
{
 get { return ReadProperty<DateTime>(CreatedDateProperty); }
 set { LoadProperty<DateTime>(CreatedDateProperty, value; }
}

In this manner, you're always working with CSLA-managed fields but you can access them in a way that is identical to private backing fields.  You could even compress the "private DateTime _createdDate" getter and setter to a single line.



Copyright (c) Marimer LLC