{"id":26012418,"url":"https://github.com/clarius/dynamically","last_synced_at":"2026-03-10T10:02:18.685Z","repository":{"id":141705704,"uuid":"566040936","full_name":"clarius/Dynamically","owner":"clarius","description":"Official docs site for https://github.com/devlooped/Dynamically","archived":false,"fork":false,"pushed_at":"2024-02-15T22:27:51.000Z","size":33,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"gh-pages","last_synced_at":"2026-02-27T09:27:25.076Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://clarius.org/Dynamically","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/clarius.png","metadata":{"files":{"readme":"readme.md","changelog":"changelog.html","contributing":null,"funding":null,"license":"license.txt","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}},"created_at":"2022-11-14T21:08:57.000Z","updated_at":"2022-11-14T21:32:54.000Z","dependencies_parsed_at":null,"dependency_job_id":"bc8ef0e3-ecb4-4898-8dbe-8a94c8af7e5d","html_url":"https://github.com/clarius/Dynamically","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/clarius/Dynamically","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarius%2FDynamically","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarius%2FDynamically/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarius%2FDynamically/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarius%2FDynamically/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clarius","download_url":"https://codeload.github.com/clarius/Dynamically/tar.gz/refs/heads/gh-pages","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarius%2FDynamically/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30329697,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":[],"created_at":"2025-03-06T00:30:52.921Z","updated_at":"2026-03-10T10:02:18.656Z","avatar_url":"https://github.com/clarius.png","language":"HTML","funding_links":["https://github.com/sponsors/devlooped","https://github.com/sponsors"],"categories":[],"sub_categories":[],"readme":"![Icon](https://github.com/devlooped/Dynamically/raw/main/assets/img/32.png) Devlooped.Dynamically\n================\n\n[![Version](https://img.shields.io/nuget/vpre/Devlooped.Dynamically.svg?color=royalblue)](https://www.nuget.org/packages/Devlooped.Dynamically)\n[![Downloads](https://img.shields.io/nuget/dt/Devlooped.Dynamically.svg?color=green)](https://www.nuget.org/packages/Devlooped.Dynamically)\n[![License](https://img.shields.io/github/license/devlooped/Dynamically.svg?color=blue)](https://github.com/devlooped/Dynamically/blob/main/license.txt)\n\n\u003c!-- #main --\u003e\nInstantiate record types from dynamic data with compatible structural shapes, \nin-memory with no reflection or serialization, via compile-time source generators.\n\n## Usage\n\nCreate records for your data types:\n\n```csharp\npublic record Point(int X, int Y);\n\npublic record Line(Point Start, Point End);\n\npublic record Drawing(Line[] Lines);\n```\n\nThis project will generate a `Dynamically` class with a factory method to create instances \nof those records from a data object with a compatible shape, such as:\n\n```csharp\nvar data = new\n{\n    Lines = new[]\n    {\n        new\n        {\n            Start = new { X = 50, Y = 0 },\n            End = new { X = 0, Y = 100 },\n        },\n        new\n        {\n            Start = new { X = 50, Y = 0 },\n            End = new { X = 0, Y = 100 },\n        }\n    }\n};\n\nDrawing drawing = Dynamically.Create\u003cDrawing\u003e(data);\n```\n\nIn adition to a dynamic object (or an [ExpandoObject](https://learn.microsoft.com/en-us/dotnet/api/system.dynamic.expandoobject?view=net-7.0), \nfor example), you can also pass in objects from other strongly typed values that come \nfrom a different assembly as long as it has the same structure. This allows fast \nin-memory object mapping without any serialization or extra allocations.\n\nThe factory works too for Newtonsoft.Json deserialized objects, for example:\n\n```csharp\n// elsewhere, you got an in-memory Json.NET object model, perhaps with:\ndynamic data = JsonConvert.DeserializeObject(json);\n\n// Subsequently, you can turn it into your strongly-typed records:\nDrawing drawing = Dynamically.Create\u003cDrawing\u003e(data);\n```\n\nYou can also optionally customize the mapping for specific records by providing accessible \nstatic `Create` or `CreateMany` factory methods in your records, so you can \nselectively customize the mapping by providing them as needed in specific cases. \nFor example:\n\n```csharp\npartial record Drawing\n{\n    // Customize creation of a single Drawing from a dynamic value\n    public static Drawing Create(dynamic value);\n    // Customize creation of a list of Drawings from a dynamic value\n    public static List\u003cDrawing\u003e CreateMany(dynamic value);\n}\n```\n\n\n## How It Works\n\nThis package analyzes (at compile-time) the shape of your records and creates a \nfactory that create instances from a dynamic object. For this, it just accesses \nthe properties of the dynamic object and passes them to the record constructor \n(or its properties). This means that the data must have (at least) the expected \nvalues for the conversion to succeed. \n\nThe static `Dynamically.Create` generic method is also generated at compile time \nand contains a switch statement that dispatches to the correct factory based on \nthe generic argument specified. \n\nIn addition, if the records are partial, you also get static `Create` and \n`CreateMany` static methods on the record type itself, for added convenience, \nsuch as:\n\n```csharp\npartial record Drawing\n{\n    public static Drawing Create(dynamic value);\n    public static List\u003cDrawing\u003e CreateMany(dynamic value);\n}\n```\n\n\u003e NOTE: these will only be provided if your record doesn't already have them.\n\n### Example\n\nFor the above example with `Drawing/Line/Point` records, you'd get a generated \n`Dynamically` type like:\n\n```csharp\nstatic partial class Dynamically\n{\n    public static partial T Create\u003cT\u003e(dynamic data)\n    {\n        return typeof(T) switch\n        {\n            Type t when t == typeof(Drawing) =\u003e (T)Drawing.Create(data),\n            _ =\u003e throw new NotSupportedException(),\n        };\n    }\n}\n```\n\nIf the `Drawing` record was partial, the `Create` method would look like:\n\n```csharp\n    partial record Drawing\n    {\n        public static Drawing Create(dynamic value)\n            =\u003e DrawingFactory.Create(value);\n    }\n```\n\nWith the `DrawingFactory` class being generated as:\n\n```csharp\nstatic partial class DrawingFactory\n{\n    public static Drawing Create(dynamic value)\n    {\n        if (value is null)\n            throw new ArgumentNullException(nameof(value));\n\n        try\n        {\n            return new Drawing(Line.CreateMany(value.Lines));\n        }\n        catch (RuntimeBinderException e)\n        {\n            var valueAsm = ((object)value).GetType().Assembly.GetName();\n            var thisAsm = typeof(DrawingFactory).Assembly.GetName();\n            throw new ArgumentException(\n                $\"Incompatible {nameof(Drawing)} value. Cannot convert value from '{valueAsm.Name}, Version={valueAsm.Version}' to '{thisAsm.Name}, Version={thisAsm.Version}'.\",\n                nameof(value), e);\n        }\n    }\n\n    public static List\u003cDrawing\u003e CreateMany(dynamic value)\n    {\n        var result = new List\u003cDrawing\u003e();\n        foreach (var item in value)\n        {\n            result.Add(Create(item));\n        }\n        return result;\n    }\n}\n```\n\nThe `Line` factory method would look very similar, instantiating a many points, \nwith perhaps `Point` being the most interesting:\n\n```csharp\nstatic partial class PointFactory\n{\n    public static Point Create(dynamic value)\n    {\n        if (value is null)\n            throw new ArgumentNullException(nameof(value));\n\n        try\n        {\n            return new Point((global::System.Int32)value.X, (global::System.Int32)value.Y);\n        }\n        catch (RuntimeBinderException e)\n        {\n            var valueAsm = ((object)value).GetType().Assembly.GetName();\n            var thisAsm = typeof(PointFactory).Assembly.GetName();\n            throw new ArgumentException(\n                $\"Incompatible {nameof(Point)} value. Cannot convert value from '{valueAsm.Name}, Version={valueAsm.Version}' to '{thisAsm.Name}, Version={thisAsm.Version}'.\",\n                nameof(value), e);\n        }\n    }\n\n    public static List\u003cPoint\u003e CreateMany(dynamic value)\n    {\n        var result = new List\u003cPoint\u003e();\n        foreach (var item in value)\n        {\n            result.Add(Create(item));\n        }\n        return result;\n    }\n}\n```\n\nAs you can see, the factory methods are very simple and straightforward, and have \ngreat run-time performance characteristics since there is absolutely no reflection, \nand the built-in C# dynamic infrastructure takes care of doing the heavy lifting. \nThe generated code is basically what you'd write manually to do the casting of the \nentire object hierarchy.\n\n## Limitations\n\nThis package is not meant to be a full-fledged object mapper. For that, you can \nuse [AutoMapper](https://automapper.org/), for example, which is much more flexible \nand has excelent [performance characteristics](https://github.com/kzu/MappingBenchmark).\nThis package does provide very fast in-memory object mapping that is far faster and \ncheaper than going through any sort of serialization. \n\nAs mentioned, the provided factories do not provide backwards-compatibility: if \nyou add a property or constructor argument to the record, the factory will fail \nfor payloads without it.\n\n\n\n\u003c!-- #main --\u003e\n\n\u003c!-- #ci --\u003e\n## Dogfooding\n\n[![CI Version](https://img.shields.io/endpoint?url=https://shields.kzu.app/vpre/Devlooped.Dynamically/main\u0026label=nuget.ci\u0026color=brightgreen)](https://pkg.kzu.app/index.json)\n[![Build](https://github.com/devlooped/Dynamically/workflows/build/badge.svg?branch=main)](https://github.com/devlooped/Dynamically/actions)\n\nWe also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced. \n\nThe CI feed is `https://pkg.kzu.app/index.json`. \n\nThe versioning scheme for packages is:\n\n- PR builds: *42.42.42-pr*`[NUMBER]`\n- Branch builds: *42.42.42-*`[BRANCH]`.`[COMMITS]`\n\n\u003c!-- #sponsors --\u003e\n\u003c!-- include https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n# Sponsors \n\n\u003c!-- sponsors.md --\u003e\n[![Clarius Org](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/clarius.png \"Clarius Org\")](https://github.com/clarius)\n[![Kirill Osenkov](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KirillOsenkov.png \"Kirill Osenkov\")](https://github.com/KirillOsenkov)\n[![MFB Technologies, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MFB-Technologies-Inc.png \"MFB Technologies, Inc.\")](https://github.com/MFB-Technologies-Inc)\n[![Stephen Shaw](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/decriptor.png \"Stephen Shaw\")](https://github.com/decriptor)\n[![Torutek](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/torutek-gh.png \"Torutek\")](https://github.com/torutek-gh)\n[![DRIVE.NET, Inc.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/drivenet.png \"DRIVE.NET, Inc.\")](https://github.com/drivenet)\n[![Daniel Gnägi](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/dgnaegi.png \"Daniel Gnägi\")](https://github.com/dgnaegi)\n[![Ashley Medway](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/AshleyMedway.png \"Ashley Medway\")](https://github.com/AshleyMedway)\n[![Keith Pickford](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Keflon.png \"Keith Pickford\")](https://github.com/Keflon)\n[![Thomas Bolon](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tbolon.png \"Thomas Bolon\")](https://github.com/tbolon)\n[![Kori Francis](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/kfrancis.png \"Kori Francis\")](https://github.com/kfrancis)\n[![Sean Killeen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/SeanKilleen.png \"Sean Killeen\")](https://github.com/SeanKilleen)\n[![Toni Wenzel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/twenzel.png \"Toni Wenzel\")](https://github.com/twenzel)\n[![Giorgi Dalakishvili](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Giorgi.png \"Giorgi Dalakishvili\")](https://github.com/Giorgi)\n[![Mike James](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/MikeCodesDotNET.png \"Mike James\")](https://github.com/MikeCodesDotNET)\n[![Dan Siegel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/dansiegel.png \"Dan Siegel\")](https://github.com/dansiegel)\n[![Reuben Swartz](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/rbnswartz.png \"Reuben Swartz\")](https://github.com/rbnswartz)\n[![Jacob Foshee](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jfoshee.png \"Jacob Foshee\")](https://github.com/jfoshee)\n[![](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Mrxx99.png \"\")](https://github.com/Mrxx99)\n[![Eric Johnson](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/eajhnsn1.png \"Eric Johnson\")](https://github.com/eajhnsn1)\n[![Norman Mackay](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/mackayn.png \"Norman Mackay\")](https://github.com/mackayn)\n[![Certify The Web](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/certifytheweb.png \"Certify The Web\")](https://github.com/certifytheweb)\n[![Ix Technologies B.V.](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/IxTechnologies.png \"Ix Technologies B.V.\")](https://github.com/IxTechnologies)\n[![David JENNI](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/davidjenni.png \"David JENNI\")](https://github.com/davidjenni)\n[![Jonathan ](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/Jonathan-Hickey.png \"Jonathan \")](https://github.com/Jonathan-Hickey)\n[![Oleg Kyrylchuk](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/okyrylchuk.png \"Oleg Kyrylchuk\")](https://github.com/okyrylchuk)\n[![Charley Wu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/akunzai.png \"Charley Wu\")](https://github.com/akunzai)\n[![Jakob Tikjøb Andersen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/jakobt.png \"Jakob Tikjøb Andersen\")](https://github.com/jakobt)\n[![Seann Alexander](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/seanalexander.png \"Seann Alexander\")](https://github.com/seanalexander)\n[![Tino Hager](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/tinohager.png \"Tino Hager\")](https://github.com/tinohager)\n[![Mark Seemann](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/ploeh.png \"Mark Seemann\")](https://github.com/ploeh)\n[![Angelo Belchior](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/angelobelchior.png \"Angelo Belchior\")](https://github.com/angelobelchior)\n[![Ken Bonny](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/KenBonny.png \"Ken Bonny\")](https://github.com/KenBonny)\n[![Simon Cropp](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/SimonCropp.png \"Simon Cropp\")](https://github.com/SimonCropp)\n[![agileworks-eu](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/agileworks-eu.png \"agileworks-eu\")](https://github.com/agileworks-eu)\n[![sorahex](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/sorahex.png \"sorahex\")](https://github.com/sorahex)\n[![Zheyu Shen](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/arsdragonfly.png \"Zheyu Shen\")](https://github.com/arsdragonfly)\n[![Vezel](https://raw.githubusercontent.com/devlooped/sponsors/main/.github/avatars/vezel-dev.png \"Vezel\")](https://github.com/vezel-dev)\n\n\n\u003c!-- sponsors.md --\u003e\n\n[![Sponsor this project](https://raw.githubusercontent.com/devlooped/sponsors/main/sponsor.png \"Sponsor this project\")](https://github.com/sponsors/devlooped)\n\u0026nbsp;\n\n[Learn more about GitHub Sponsors](https://github.com/sponsors)\n\n\u003c!-- https://github.com/devlooped/sponsors/raw/main/footer.md --\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclarius%2Fdynamically","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclarius%2Fdynamically","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclarius%2Fdynamically/lists"}