{"id":22726853,"url":"https://github.com/nuclex-shared-dotnet/nuclex.support","last_synced_at":"2025-03-30T00:15:25.389Z","repository":{"id":250318447,"uuid":"834115960","full_name":"nuclex-shared-dotnet/Nuclex.Support","owner":"nuclex-shared-dotnet","description":"Library of supporting code for .NET. Observable collections, settings storage registry and .ini files, deep object cloning, command line parser, stream chaining and segmenting, license key transformation and many more things.","archived":false,"fork":false,"pushed_at":"2024-08-05T12:34:20.000Z","size":1122,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-02-05T01:48:35.883Z","etag":null,"topics":["cloning","ini-parser","object-cloning","observable","observer-pattern","registry","settings","settings-storage"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nuclex-shared-dotnet.png","metadata":{"files":{"readme":"ReadMe.md","changelog":null,"contributing":null,"funding":null,"license":"License.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-07-26T13:00:54.000Z","updated_at":"2024-08-05T12:34:29.000Z","dependencies_parsed_at":null,"dependency_job_id":"7798756b-38f0-4568-98a6-1ff9a55d56db","html_url":"https://github.com/nuclex-shared-dotnet/Nuclex.Support","commit_stats":null,"previous_names":["nuclex-shared-dotnet/nuclex.support"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuclex-shared-dotnet%2FNuclex.Support","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuclex-shared-dotnet%2FNuclex.Support/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuclex-shared-dotnet%2FNuclex.Support/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nuclex-shared-dotnet%2FNuclex.Support/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nuclex-shared-dotnet","download_url":"https://codeload.github.com/nuclex-shared-dotnet/Nuclex.Support/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246258873,"owners_count":20748573,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cloning","ini-parser","object-cloning","observable","observer-pattern","registry","settings","settings-storage"],"created_at":"2024-12-10T17:07:11.236Z","updated_at":"2025-03-30T00:15:25.368Z","avatar_url":"https://github.com/nuclex-shared-dotnet.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"Nuclex.Support ![Developed on Linux, works well on Windows](./Documents/images/platforms-linux-windows-badge.svg) ![Several projects are using library and it has received extensive testting](./Documents/images/status-mature-and-stable-badge.svg)\n==============\n\nThis library aims to be your trusty toolbox of supporting code for\nproblems that come up in any type of project. It consists of carefully\nchosen and well-designed pieces that aid you in dealing with settings\nstorage, change notifications, stream processing, object cloning and more.\n\nThere are unit tests for the whole library, so everything is verifiably\nworking on all platforms tested (Linux, Windows, Raspberry).\n\n\nObject Cloning\n--------------\n\nWhether you use the prototye design patten on complex objects or have another\nreason, sometimes a deep clone of an object tree is needed. This library\nprovides three complete solutions to cloning objects in .NET:\n\n- The `SerializationCloner`. It uses .NET's BinarySerializer in a way that\n  will serialize your object tree regardless of whether your objects have\n  the `Serializable` attribute or not. This is the slowest, least efficient\n  object cloner, but it relies on built-in .NET classes only.\n\n- The `ReflectionCloner` uses .NET's reflection capabilities (that means\n  interrogating an object what fields and properties it has) to create\n  complete clones of an object, including any arrays and referenced objects.\n  This serializer has no setup time and has pretty decent performance.\n\n- The `ExpressionTreeCloner` uses Linq expression trees to generate tailored\n  cloning code for your classes at runtime. This method of cloning has a setup\n  time (meaning it takes longer the first time it is confronted with a new\n  class), but from the second clone onwards, is much faster than the others.\n\nAll three object cloners can create *shallow clones* (meaning any references\nto other object will be kept without copying the referenced objects, too) and\n*deep clones* meaning any refeferenced objects (and their referenced objects)\nwill be cloned as well. Careful, this means event subscribers, such a forms\nand unexpected hangers-on will be cloned, too.\n\nFurthermore, all three object cloners can create *property-based clones*\n(where only those settings exposed via properties are cloned), which may skip\nthe non-exposed parts of an object, as well as *field-based clones* which\nreplicate all the data of a class - any private field and hidden state.\n\n```csharp\nclass Example {\n  public Example(Example child = null) {\n    Child = child;\n  }\n  public Example Child { get; private set; }\n}\n\nclass Test {\n  public static void CloneSomething() {\n    var test = new Example(new Example());\n\n    var reflectionCloner = new ReflectionCloner();\n    var clone = reflectionCloner.DeepFieldClone(test);\n\n    // Clone is now a complete copy of test, including the child object\n  }\n}\n```\n\n\nSettings\n--------\n\nMany applications have to store their settings in an external file or,\nfor pure Windows applications, in the registry. This can be tedious and\ndifficult to unit test, too. Nuclex.Support provides an autonomous ini\nparser (which works cross-platform and does **not** rely on\n`GetPrivateProfileString`).\n\nFurthermore, it uses an interface to provide the same functionality for\nthe Registry and in-memory settings. This lets you switch between storing\nyour settings in the registry, in an .ini file or constructing a settings\ncontainer in memory to appropriately unit-test your code with mock data.\n\n```csharp\nstatic readonly string BasicCategoryName = \"Basic\";\nstatic readonly string HintsCategoryName = \"Hints\";\n\nvoid saveSettings(ISettingStore settingsStore) {\n  settingsStore.Set(BasicCategoryName, \"AskSaveOnQuit\", this.askSaveOnQuit);\n  settingsStore.Set(BasicCategoryName, \"ActivePanel\", this.activePanelIndex);\n  settingsStore.Set(HintsCategoryName, \"ShowNameHint\", this.showNameHint);\n  // ...\n}\n\nvoid saveSettingsToIni() {\n  var iniStore = new ConfigurationFileStore();\n  saveSettings(iniStore);\n\n  using(var writer = new StreamWriteR(\"awesome-app.ini\")) {\n    iniStore.Save(writer);\n    writer.Flush()\n  }\n}\n\nvoid saveSettingsToRegistry() {\n  using(\n    var registryStore = new WindowsRegistryStore(\n      RegistryHive.HKCU, \"AwesomeApplication\"\n    )\n  ) {\n    saveSettings(registryStore);\n  }\n}\n```\n\nObservable Base Class\n---------------------\n\n.NET provides the `INotifyPropertyChanged` interface for objects to expose\nan event that reports when a property of the object has changed. This is\nused by data binding UI controls and some ORMs to detect when an object has\nbeen changed and the UI or database need to be updated.\n\nIt is a bit tedious to implement, so here's a base class to make it much\nmore pleasant to use:\n\n```csharp\nclass CreateUserViewModel : Observable {\n\n  public string FirstName {\n    get { return this.firstName; }\n    set {\n      if(value != this.firstName) {\n        this.firstName = value;\n        OnPropertyChanged(nameof(FirstName));\n      }\n    }\n  }\n\n  private string firstName;\n\n}\n```\n\nThere's an extension method for the consuming side, too, with proper handling\nof *wildcard* change notifications that are often overlooked:\n\n```csharp\nCreateUserViewModel ViewModel { get; set; } \n\nvoid onPropertyChanged(object sender, PropertyChangedEventArgs arguments) {\n  if(arguments.AreAffecting(nameof(ViewModel.FirstName))) {\n    this.firstNameLine.Text = ViewModel.FirstName;\n  }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuclex-shared-dotnet%2Fnuclex.support","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnuclex-shared-dotnet%2Fnuclex.support","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnuclex-shared-dotnet%2Fnuclex.support/lists"}