Open Chicagoan2016 opened 7 years ago
RegisterProperty(x => x.MyString, "My string friendlyname", "MyStringDefaultValue");
Thanks @ajj7060 , In the RuleTutorial sample, under project CompareFieldsRules there is a property declaration of
public static readonly PropertyInfo
If I am not mistaken here the default value is the current datetime? boy,writing this kind of code does make me look like a real software developer : ) which is cool, right?
kind regards
The default value will be a date time. You'd have to test it though, I suspect that doesn't do what you think it does, which is get the current date time at the time the BO containing that property definition is created. I'm betting every single instance of the BO will have the time of the first BO's creation.
i've been bitten by that once, but trying to put new MobileList<string>
as the default. It didn't work, because EVERY instance of the BO was sharing a single instance of the MobileList. Which of course caused some very hard to track down problems...
Actually that'd be a nice feature, RegisterProperty which takes a Func
It is important to understand the difference between value type and reference types.
Default value on RegisterProperty only works as expected for value type.
SmartDate is a "struct" (which is a value type) and MobileList
See: https://msdn.microsoft.com/en-us/library/4d43ts61%28v=vs.90%29.aspx?f=255&MSPPError=-2147217396 and http://www.albahari.com/valuevsreftypes.aspx
And the reasoning behind this is that a reference type (typically a child list/child object) should either be set to a default value in DataPortal_Create/Child_Create or be loaded in DataPortal_Fetch or be lazy loaded when the property getter is called the first time.
Thanks Jonny, I'm familiar with how reference types and value types work; my attempt to set MobileList
public static readonly PropertyInfo StartDateProperty = RegisterProperty(c => c.StartDate, null, new SmartDate() {Date = new Func(() => DateTime.Now).Invoke()});
Its clear that the intent of that code is for the BO to have StartDate set to whatever time it is when the BO instance gets created. What actually happens is all BOs get a StartDate which is the time the RegisterProperty call was made (which happens only once).
Consider the following program which uses the above RegisterProperty call.
using System;
using System.Threading;
using Csla;
namespace CslaDefaultValues {
internal class Program {
internal static void Main(string[] args) {
var bo1 = MyBO.NewBO();
Thread.Sleep(new TimeSpan(0, 0, 0, 5));
var bo2 = MyBO.NewBO();
Console.WriteLine($"MyBO1.Date = {bo1.StartDate.Date}, MyBO2.Date = {bo2.StartDate.Date}");
Console.ReadLine();
}
}
[Serializable]
public sealed class MyBO : BusinessBase<MyBO> {
public static readonly PropertyInfo<SmartDate> StartDateProperty =
RegisterProperty(c => c.StartDate, null, new SmartDate { Date = new Func<DateTime>(() => DateTime.Now).Invoke() });
public SmartDate StartDate {
get => GetProperty(StartDateProperty);
set => SetProperty(StartDateProperty, value);
}
public static MyBO NewBO() => DataPortal.Create<MyBO>();
protected override void DataPortal_Create() {
BusinessRules.CheckRules();
}
}
}
Again, the intent of the developer would be that bo2.StartDate
's value is five seconds after bo1
.
My point was that this is due to the defaultValue being a T
instead of Func<T>
. If there were an overload of RegisterProperty which took Func<T>
then we could do what is attempted here; eg:
public static readonly PropertyInfo<SmartDate> StartDateProperty = RegisterProperty(c => c.StartDate, null, () => new SmartDate { Date = DateTime.Now });
That would work as expected. But today in order to use the current value of DateTime.Now
you need to do that in a XYZ_Create data portal method, and that has nothing to do with reference vs. value type. Now, maybe there is some issue with taking a Func<T>
in RegisterProperty that occurs becomes of something in the framework, but the lack of such an overload is why you need to do stuff like this in the data portal method.
Ok, I see the issue now.
Thanks @ajj7060 , I am glad you explained this with sample code, I have to go back and change some code. I forgot the way RegisterProperty method works and thought the default value would work like regular non-csla properties.
Regards
I wonder if we should look at an overload that accepts an Action that you can supply to initialize the value?
@rockfordlhotka , do you mean a new overload? or one of the nine overloads currently available.
kind regards
@rockfordlhotka That'd be a nice addition I think, personally. Its not a huge issue I think, but the way things currently are some of the initialization is in the RegisterProperty calls, and other other in the _Create DP methods, so to see how everything overall is initialized you need to look in multiple places. An Action<T>
might let people do all the defaulting in RegisterProperty, like this:
public static readonly PropertyInfo<ChildList> ChildrenProperty = RegisterProperty("Children", () => ChildList.NewChildList())
Not sure if that'd actually be a good idea though 😆
If this gets added, I can take the ticket. I need a reason to learn Github better :-/
I know this question is very basic : ), I have a string read/write csla managed property and I want to have a default value for that property, I am kinda confused about the different overloads of RegisterProperty() what will be the correct syntax of Register property method for this scenario?
regards