No constructor, lazy initialization and auto properties

Mar 31, 2009 at 10:55 AM
Edited Mar 31, 2009 at 11:56 AM
Hello, I would give some feedback:
  1. I would suggest to never include a constructor in the generated classes, that because they are partial,  so it possible to add your own constructor in the other partial class.
    Another solution would be to add a partial method (require C# 3.0) called from the constructor:
    public X(){this.InternalInit();}
    partial void InternalInit();
  2. Add the initialization of the collections in the property according the lazy pattern:
    get{if (this.xField==null) this.xFiled=new X(); return this.xField;}
  3. Use C# 3.0 auto properties when no special get or set is required:
    public X x{get; set;}
  4. Add the option to generate the code for the "Parent" property when observable collection are used: By adding a new object to a collection the parent is set to the object holding the collection. By removing the object from the collection the parent is cleared:
    this.xsField.CollectionChanged += (object sender, NotifyCollectionChangedEventArgs e) =>
    {
      if (e.NewItems!=null) foreach (X x in e.NewItems) {if (x.Parent!=null) x.Parent.Xs.Remove(x); x.Parent=this;}
      if (e.OldItems!=null) foreach (X x in e.OldItems) x.Parent = null;
    };
    public XParent Parent{get; internal protected set;}
    PS: Also the parent pattern can be added in the lazy initialization of the property
  5. Wrap the generated classes and properties in #region
Regards
Coordinator
May 21, 2009 at 1:27 PM

Thank you for all your suggestion.

I’m working on this.

Pascal.

De : aquilax [mailto:notifications@codeplex.com]
Envoyé : mardi 31 mars 2009 12:56
À : pascal.cabanel@free.fr
Objet : No constructor, lazy initialization and auto properties [Xsd2Code:51817]

From: aquilax

Hello, I would give some feedback:

1. I would suggest to never include a constructor in the generated classes, that because they are partial, so it possible to add your own constructor in the other partial class.
Another solution would be to add a partial method (require C# 3.0) called from the constructor:
public X(){this.InternalInit();}
partial void InternalInit();

2. Add the initialization of the collections in the property according the lazy pattern:
get{if (this.xField==null) this.xFiled=new X(); return this.xField;}

3. Use C# 3.0 auto properties when no special get or set is required:
public X x{get; set;}

Regards

Read the full discussion online.

To add a post to this discussion, reply to this email (Xsd2Code@discussions.codeplex.com)

To start a new discussion for this project, email Xsd2Code@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com

May 26, 2009 at 9:20 AM
Edited May 26, 2009 at 9:28 AM

In the meantime I have strong modified the generated code because I needed more flexibility in the implementation of the business logic in the partial class. I ended up with a base class structure which reduce the theoretical generated code to 20-30%. A base class is very useful in case you have to implement the INotifyPropertyChanged, my base class is quite complex, but to give you an idea I will reduce it to the fondamental functions. Anyway this is also to suggest the option to add a base class for the generated classes, like typed dataset in VS2005.

The two main methods are to set the field value and to notify the property change:

public abstract partial class BaseItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

protected virtual void NotifyPropertyChange(string propertyName)
{
if (!string.IsNullOrEmpty(propertyName)) this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}

protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null) handler(this, e);
}

protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue)
{
if (!Object.Equals(oldValue, newValue))
{
oldValue = newValue;
this.NotifyPropertyChange(propertyName);
}
}
}

Now with this base class all the properties in the generated classes look like:

  public ObservableCollection<ObjectX> XObjects
{
get { return this.xObjectsField ?? (this.XObjects = new ObservableCollection<ObjectX>()); }
set { base.SetPropertyValue<ObservableCollection<ObjectX>>("XObjects", ref this.xObjectsField , value); }
}

public int Id
{
get { return this.idField; }
set { base.SetPropertyValue<int>("Id", ref this.idField, value); }
}

//Setting the default value attribute will also reduce the serialized xml
[DefaultValueAttribute("Default Value")]
public string Name
{
get { return this.nameField ?? (this.nameField = "Default Value"); }
set { base.SetPropertyValue<string>("Name", ref this.nameField, value); }
}

This will reduce the generated code to 20%-30% of the actual one. Some other useful methods in the base class are to suspend the property change notification, to handle the change of the properties fields and to serialize the object:

public abstract partial class BaseItem : INotifyPropertyChanged
{
//Resume, suspend and get property change notification state
private bool _suspendPropertiesChangeNotification;
public bool IsPropertiesChangeNotificationSuspended() { return this._suspendPropertiesChangeNotification; }
public void ResumePropertiesChangeNotification() { this._suspendPropertiesChangeNotification = false; }
public void SuspendPropertiesChangeNotification() { this._suspendPropertiesChangeNotification = true; }

//Internal handlers to control the properties changes
protected virtual void ChangingProperty<T>(string propertyName, T oldValue, ref T newValue, ref bool acceptChange) { }
protected virtual void ChangedProperty<T>(string propertyName, T oldValue, T newValue) { }

//Notify property change, to override for a light way to handle properties changes
protected virtual void NotifyPropertyChange(string propertyName, object newValue) { this.NotifyPropertyChange(propertyName, newValue, true); }
protected virtual void NotifyPropertyChange(string propertyName, object newValue, bool notifyChange)
{
if (!string.IsNullOrEmpty(propertyName) && !this.IsPropertiesChangeNotificationSuspended() && notifyChange) this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
{
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null) handler(this, e);
}

//Setting property value
protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue) { return this.SetPropertyValue<T>(propertyName, ref oldValue, newValue, true, null); }
protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue, bool notifyChange, Action<string, T, T> changedHandler)
{
if (!Object.Equals(oldValue, newValue))
{
bool flag1 = true;
this.ChangingProperty<T>(propertyName, oldValue, ref newValue, ref flag1);
if (flag1)
{
T obj1 = oldValue;
oldValue = newValue;
if (changedHandler != null) changedHandler(propertyName, obj1, newValue);
this.ChangedProperty<T>(propertyName, obj1, newValue);
this.NotifyPropertyChange(propertyName, newValue, notifyChange);
}
}
}

//Deserialization and Serialization
protected static T Deserialize<T>(Stream stream)
{
return (T)new XmlSerializer(typeof(T)).Deserialize(XmlReader.Create(stream));
}

protected static void Serialize<T>(Stream stream, T item)
{
new XmlSerializer(typeof(T)).Serialize(stream, item);
}

//Load and Save
protected static T Load<T>(string path)
{
using(FileStream stream = File.OpenRead(path))
{
try{ return this.Deserialize<T>(stream); }
finally{ stream.Close(); }
}
}

protected static void Save<T>(string path, T item)
{
using(FileStream stream = File.Create(path))
{
try{ this.Serialize<T>(stream, item); }
finally{ stream.Close(); }
}
}
}

Sure this base class can be still optimized, but it gives already an incredibility control over the data flow in the generated classes.

PS: I forgot to say that it would be nicer to use the .NET style for private fields with the underscore as prefix, instead of the "Field" word as suffix: private int idField ---> private int _id;

Coordinator
May 27, 2009 at 8:24 PM

Hello,

The idea of using a base class with generic is very interesting.

I already had this idea.

But yet I try to fix every bug. Right now many people use Xsd2Code.

So I decided to defer this type of development.
If you wish, you can send me your changes so that I can think about it for next release.
Good work !

Pascal.

De : Aquilax [mailto:notifications@codeplex.com]
Envoyé : mardi 26 mai 2009 11:21
À : pascal.cabanel@free.fr
Objet : Re: No constructor, lazy initialization and auto properties [Xsd2Code:51817]

From: Aquilax

In the meantime I have strong modified the generated code because I needed more flexibility in the implementation of the business logic in the partial class. I ended up with a base class structure which reduce the theoretical generated code to 20-30%. A base class is very useful in case you have to implement the INotifyPropertyChanged, my base class is quite complex, but to give you an idea I will reduce it to the fondamental functions. Anyway this is also to suggest the option to add a base class for the generated classes, like typed dataset in VS2005.

The two main methods are to set the field value and to notify the property change:

public abstract partial class BaseItem : INotifyPropertyChanged
{
  public event PropertyChangedEventHandler PropertyChanged;
 
  protected virtual void NotifyPropertyChange(string propertyName)
  {
    if (!string.IsNullOrEmpty(propertyName)) this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  }
 
  protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
  {
    PropertyChangedEventHandler handler = this.PropertyChanged;
    if (handler != null) handler(this, e);
  }
 
  protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue)
  {
     if (!Object.Equals(oldValue, newValue))
     {
       oldValue = newValue;
       this.NotifyPropertyChange(propertyName);
     }
  }
}

Now with this base class all the properties in the generated classes look like:

  public ObservableCollection<ObjectX> XObjects
  {
    get { return this.xObjectsField ?? (this.XObjects = new ObservableCollection<ObjectX>()); }
    set { base.SetPropertyValue<ObservableCollection<ObjectX>>("XObjects", ref this.xObjectsField , value); }
  }
 
  public int Id
  {
    get { return this.idField; }
    set { base.SetPropertyValue<int>("Id", ref this.idField, value); }
  }
 
  //Setting the default value attribute will also reduce the serialized xml
  [DefaultValueAttribute("Default Value")]
  public string Name
  {
    get { return this.nameField ?? (this.nameField="Default Value"); }
    set { base.SetPropertyValue<string >("Name", ref this.nameField, value); }
  }

This will reduce the generated code to 20%-30% of the actual one. Some other useful methods in the base class are to suspend the property change notification, to handle the change of the properties fields and to serialize the object:

public abstract partial class BaseItem : INotifyPropertyChanged
{
  //Resume, suspend and get property change notification state
  private bool _suspendPropertiesChangeNotification;
  public bool IsPropertiesChangeNotificationSuspended() { return this._suspendPropertiesChangeNotification; }
  public void ResumePropertiesChangeNotification() { this._suspendPropertiesChangeNotification = false; }
  public void SuspendPropertiesChangeNotification() { this._suspendPropertiesChangeNotification = true; }
 
  //Internal handlers to control the properties changes
  protected virtual void ChangingProperty<T>(string propertyName, T oldValue, ref T newValue, ref bool acceptChange) { }
  protected virtual void ChangedProperty<T>(string propertyName, T oldValue, T newValue) { }
 
  //Notify property change, to override for a light way to handle properties changes
  protected virtual void NotifyPropertyChange(string propertyName, object newValue)  { this.NotifyPropertyChange(propertyName, newValue, true); }
  protected virtual void NotifyPropertyChange(string propertyName, object newValue, bool notifyChange)
  {
    if (!string.IsNullOrEmpty(propertyName) && !this.IsPropertiesChangeNotificationSuspended() && notifyChange) this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
  }
  protected virtual void OnPropertyChanged(PropertyChangedEventArgs e)
  {
     PropertyChangedEventHandler handler = this.PropertyChanged;
     if (handler != null) handler(this, e);
  }
 
  //Setting property value
  protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue) { return this.SetPropertyValue<T>(propertyName, ref oldValue, newValue, true, null); }
  protected void SetPropertyValue<T>(string propertyName, ref T oldValue, T newValue, bool notifyChange, Action<string, T, T> changedHandler)
  {
    if (!Object.Equals(oldValue, newValue))
    {
      bool flag1 = true;
      this.ChangingProperty<T>(propertyName, oldValue, ref newValue, ref flag1);
      if (flag1)
      {
        T obj1 = oldValue;
        oldValue = newValue;
        if (changedHandler != null) changedHandler(propertyName, obj1, newValue);
        this.ChangedProperty<T>(propertyName, obj1, newValue);
        this.NotifyPropertyChange(propertyName, newValue, notifyChange);
      }
    }
  }
 
  //Deserialization and Serialization
  protected static T Deserialize<T>(Stream stream)
  {
    return (T)new XmlSerializer(typeof(T)).Deserialize(XmlReader.Create(stream));
  }
 
  protected static void Serialize<T>(Stream stream, T item)
  {
    new XmlSerializer(typeof(T)).Serialize(stream, item);
  }
 
  //Load and Save
  protected static T Load<T>(string path) 
  {
    using(FileStream stream = File.OpenRead(path))
    {
      try{ return this.Deserialize<T>(stream); }
      finally{ stream.Close(); }
    }
  }
 
  protected static void Save<T>(string path, T item) 
  {
    using(FileStream stream = File.Create(path))
    {
       try{ this.Serialize<T>(stream, item); }
       finally{ stream.Close(); }
    }
  }
}

Sure this base class can be still optimized, but it gives already an incredibility control over the data flow in the generated classes.

Read the full discussion online.

To add a post to this discussion, reply to this email (Xsd2Code@discussions.codeplex.com)

To start a new discussion for this project, email Xsd2Code@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com