Wrote a short ReadMe file for Nuclex.Support
This commit is contained in:
		
							parent
							
								
									705ec87d5d
								
							
						
					
					
						commit
						8f9b5ef19c
					
				
					 1 changed files with 143 additions and 0 deletions
				
			
		
							
								
								
									
										143
									
								
								ReadMe.md
									
										
									
									
									
								
							
							
						
						
									
										143
									
								
								ReadMe.md
									
										
									
									
									
								
							| 
						 | 
					@ -14,3 +14,146 @@ storage, change notifications, stream processing, object cloning and more.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
There are unit tests for the whole library, so everything is verifiably
 | 
					There are unit tests for the whole library, so everything is verifiably
 | 
				
			||||||
working on all platforms tested (Linux, Windows, Raspberry).
 | 
					working on all platforms tested (Linux, Windows, Raspberry).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Object Cloning
 | 
				
			||||||
 | 
					--------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Whether you use the prototye design patten on complex objects or have another
 | 
				
			||||||
 | 
					reason, sometimes a deep clone of an object tree is needed. This library
 | 
				
			||||||
 | 
					provides three complete solutions to cloning objects in .NET:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `SerializationCloner`. It uses .NET's BinarySerializer in a way that
 | 
				
			||||||
 | 
					  will serialize your object tree regardless of whether your objects have
 | 
				
			||||||
 | 
					  the `Serializable` attribute or not. This is the slowest, least efficient
 | 
				
			||||||
 | 
					  object cloner, but it relies on built-in .NET classes only.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `ReflectionCloner` uses .NET's reflection capabilities (that means
 | 
				
			||||||
 | 
					  interrogating an object what fields and properties it has) to create
 | 
				
			||||||
 | 
					  complete clones of an object, including any arrays and referenced objects.
 | 
				
			||||||
 | 
					  This serializer has no setup time and has pretty decent performance.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- The `ExpressionTreeCloner` uses Linq expression trees to generate tailored
 | 
				
			||||||
 | 
					  cloning code for your classes at runtime. This method of cloning has a setup
 | 
				
			||||||
 | 
					  time (meaning it takes longer the first time it is confronted with a new
 | 
				
			||||||
 | 
					  class), but from the second clone onwards, is much faster than the others.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					All three object cloners can create *shallow clones* (meaning any references
 | 
				
			||||||
 | 
					to other object will be kept without copying the referenced objects, too) and
 | 
				
			||||||
 | 
					*deep clones* meaning any refeferenced objects (and their referenced objects)
 | 
				
			||||||
 | 
					will be cloned as well. Careful, this means event subscribers, such a forms
 | 
				
			||||||
 | 
					and unexpected hangers-on will be cloned, too.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Furthermore, all three object cloners can create *property-based clones*
 | 
				
			||||||
 | 
					(where only those settings exposed via properties are cloned), which may skip
 | 
				
			||||||
 | 
					the non-exposed parts of an object, as well as *field-based clones* which
 | 
				
			||||||
 | 
					replicate all the data of a class - any private field and hidden state.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp
 | 
				
			||||||
 | 
					class Example {
 | 
				
			||||||
 | 
					  public Example(Example child = null) {
 | 
				
			||||||
 | 
					  	Child = child;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  public Example Child { get; private set; }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Test {
 | 
				
			||||||
 | 
					  public static void CloneSomething() {
 | 
				
			||||||
 | 
					  	var test = new Example(new Example());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  	var reflectionCloner = new ReflectionCloner();
 | 
				
			||||||
 | 
					  	var clone = reflectionCloner.DeepFieldClone(test);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Clone is now a complete copy of test, including the child object
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Settings
 | 
				
			||||||
 | 
					--------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Many applications have to store their settings in an external file or,
 | 
				
			||||||
 | 
					for pure Windows applications, in the registry. This can be tedious and
 | 
				
			||||||
 | 
					difficult to unit test, too. Nuclex.Support provides an autonomous ini
 | 
				
			||||||
 | 
					parser (which works cross-platform and does **not** rely on
 | 
				
			||||||
 | 
					`GetPrivateProfileString`).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Furthermore, it uses an interface to provide the same functionality for
 | 
				
			||||||
 | 
					the Registry and in-memory settings. This lets you switch between storing
 | 
				
			||||||
 | 
					your settings in the registry, in an .ini file or constructing a settings
 | 
				
			||||||
 | 
					container in memory to appropriately unit-test your code with mock data.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp
 | 
				
			||||||
 | 
					static readonly string BasicCategoryName = "Basic";
 | 
				
			||||||
 | 
					static readonly string HintsCategoryName = "Hints";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void saveSettings(ISettingStore settingsStore) {
 | 
				
			||||||
 | 
					  settingsStore.Set(BasicCategoryName, "AskSaveOnQuit", this.askSaveOnQuit);
 | 
				
			||||||
 | 
					  settingsStore.Set(BasicCategoryName, "ActivePanel", this.activePanelIndex);
 | 
				
			||||||
 | 
					  settingsStore.Set(HintsCategoryName, "ShowNameHint", this.showNameHint);
 | 
				
			||||||
 | 
					  // ...
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void saveSettingsToIni() {
 | 
				
			||||||
 | 
					  var iniStore = new ConfigurationFileStore();
 | 
				
			||||||
 | 
					  saveSettings(iniStore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  using(var writer = new StreamWriteR("awesome-app.ini")) {
 | 
				
			||||||
 | 
					  	iniStore.Save(writer);
 | 
				
			||||||
 | 
					  	writer.Flush()
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void saveSettingsToRegistry() {
 | 
				
			||||||
 | 
					  using(
 | 
				
			||||||
 | 
					  	var registryStore = new WindowsRegistryStore(
 | 
				
			||||||
 | 
					  	  RegistryHive.HKCU, "AwesomeApplication"
 | 
				
			||||||
 | 
					    )
 | 
				
			||||||
 | 
					  ) {
 | 
				
			||||||
 | 
					  	saveSettings(registryStore);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Observable Base Class
 | 
				
			||||||
 | 
					---------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.NET provides the `INotifyPropertyChanged` interface for objects to expose
 | 
				
			||||||
 | 
					an event that reports when a property of the object has changed. This is
 | 
				
			||||||
 | 
					used by data binding UI controls and some ORMs to detect when an object has
 | 
				
			||||||
 | 
					been changed and the UI or database need to be updated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It is a bit tedious to implement, so here's a base class to make it much
 | 
				
			||||||
 | 
					more pleasant to use:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp
 | 
				
			||||||
 | 
					class CreateUserViewModel : Observable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  public string FirstName {
 | 
				
			||||||
 | 
					  	get { return this.firstName; }
 | 
				
			||||||
 | 
					  	set {
 | 
				
			||||||
 | 
					  	  if(value != this.firstName) {
 | 
				
			||||||
 | 
					  	  	this.firstName = value;
 | 
				
			||||||
 | 
					  	  	OnPropertyChanged(nameof(FirstName));
 | 
				
			||||||
 | 
					  	  }
 | 
				
			||||||
 | 
					  	}
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private string firstName;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There's an extension method for the consuming side, too, with proper handling
 | 
				
			||||||
 | 
					of *wildcard* change notifications that are often overlooked:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```csharp
 | 
				
			||||||
 | 
					CreateUserViewModel ViewModel { get; set; } 
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void onPropertyChanged(object sender, PropertyChangedEventArgs arguments) {
 | 
				
			||||||
 | 
					  if(arguments.AreAffecting(nameof(ViewModel.FirstName))) {
 | 
				
			||||||
 | 
					  	this.firstNameLine.Text = ViewModel.FirstName;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue