{"id":15410000,"url":"https://github.com/smatsson/chainly","last_synced_at":"2026-03-09T19:01:43.689Z","repository":{"id":70576123,"uuid":"77025199","full_name":"smatsson/Chainly","owner":"smatsson","description":"Make any .NET object a fluent interface regardless if you have the source code or not!","archived":false,"fork":false,"pushed_at":"2017-09-15T11:21:52.000Z","size":27,"stargazers_count":21,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-14T00:09:55.786Z","etag":null,"topics":["chainable-methods","fluent-interface"],"latest_commit_sha":null,"homepage":"","language":"C#","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/smatsson.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2016-12-21T06:36:07.000Z","updated_at":"2023-12-23T19:08:05.000Z","dependencies_parsed_at":null,"dependency_job_id":"c57c31dd-c994-4b8f-84ba-50d8f703e3e6","html_url":"https://github.com/smatsson/Chainly","commit_stats":{"total_commits":14,"total_committers":2,"mean_commits":7.0,"dds":0.4285714285714286,"last_synced_commit":"8058263603f5d6ea5da1d0eeec5288d39a58bb83"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smatsson%2FChainly","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smatsson%2FChainly/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smatsson%2FChainly/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smatsson%2FChainly/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smatsson","download_url":"https://codeload.github.com/smatsson/Chainly/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249195305,"owners_count":21228169,"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":["chainable-methods","fluent-interface"],"created_at":"2024-10-01T16:42:14.325Z","updated_at":"2026-03-09T19:01:38.649Z","avatar_url":"https://github.com/smatsson.png","language":"C#","readme":"# Chainly\nMake any .NET object a fluent interface regardless if you have the source code or not!\n\n[![NuGet](https://img.shields.io/nuget/v/Chainly.svg)](https://www.nuget.org/packages/Chainly)\n\n``PM\u003e Install-Package Chainly``\n\n# Reflection.Emit method\n\n## Example\n\nGiven a class `Asdf` we define an interface `IAsdfChain`. We then run the `Chain` extension on the `Asdf` instance and voila! Fluent interface! :) \n\n```csharp\nvar myString = new Asdf(\"This is my string!\")\n\t\t\t\t.Chain\u003cIAsdfChain\u003e()\n\t\t\t\t.SomeMethod()\n\t\t\t\t.ParameterMethod(\"A\", 123)\n\t\t\t\t.Value() // Call .Value() to get the unchained Asdf instance\n\t\t\t\t.GetMyString();\n// myString == \"This is my string!\"\n\npublic class Asdf\n{\n\tprivate readonly string _myString;\n\n\tpublic int SomeMethodCount { get; set; }\n\tpublic int ParameterMethodWithTwoParametersCount { get; set; }\n\n\tpublic Asdf(string myString)\n\t{\n\t\t_myString = myString;\n\t}\n\n\tpublic void SomeMethod()\n\t{\n\t\tSomeMethodCount++;\n\t}\n\n\tpublic void ParameterMethod(string value, int otherValue)\n\t{\n\t\tParameterMethodWithTwoParametersCount++;\n\t}\n\n\tpublic string GetMyString()\n\t{\n\t\treturn _myString;\n\t}\n}\n\n// Only methods defined in this interface will be made fluent. Other methods will be left alone.\npublic interface IAsdfChain\n{\n\tIAsdfChain SomeMethod();\n\tIAsdfChain ParameterMethod(string value, int value2);\n\t// Value is a special method, returning the original unchained object.\n\tAsdf Value();\n}\n\n```\n\nOf course it also works with built in classes! \n\n```csharp\nvar buffer = new char[2];\nvar asdfUpper = \"asdf\".Chain\u003cIChainString\u003e().CopyTo(0, buffer, 0, 2).Value().ToUpper();\n// buffer == ['a', 's']\n// asdfUpper = ASDF\n\nvar elapsed = StopWatch.StartNew().Chain\u003cIStopWatchChain\u003e().Stop().Value().Elapsed;\n\npublic interface IChainString\n{\n\tIChainString CopyTo(int sourceIndex, char[] destination, int destinationIndex, int count);\n\tstring Value();\n}\n\npublic interface IStopWatchChain\n{\n\tIStopWatchChain Stop();\n\tStopwatch Value();\n}\n\n```\n\n## What are the steps to make an object fluent?\n* Create an interface. You can call it anything you'd like but it must be public.\n* Add each void method you want to make fluent to the interface and use the interface as return type (not all void methods are required, only the ones you wish to make fluent).\n* Add a Value method with the object type as return value.\n* Run Chain\u003c{interfacename}\u003e on the object to make it fluent.\n\n### Example\n\n```csharp\npublic interface IMyInterface\n{\n\tIMyInterface SomeVoidMethod(string param1, int param2);\n\tobject Value();\n}\n\nobjectWithSomeVoidMethod = objectWithSomeVoidMethod\n\t\t\t\t\t\t\t.Chain\u003cIMyInterface\u003e\n\t\t\t\t\t\t\t.SomeVoidMethod(\"A\", 1)\n\t\t\t\t\t\t\t.SomeVoidMethod(\"B\", 2)\n\t\t\t\t\t\t\t.Value();\n\n```\n\n# Action based method\n\n## Summary\nThe action based method allows chaining for any type without the need for an interface.\n\n## Example\n```csharp\nvar model = new Asdf(\"a\");\n\nvar myString = model.Chain()\n\t.Do(m =\u003e m.ParameterMethod(\"b\"))\n\t.Do(m =\u003e m.ParameterMethod(\"c\"))\n\t.Do(m =\u003e m.ParameterMethod(\"d\", 1))\n\t.Value()\n\t.GetMyString();\n```\n\n## Overloaded Operator Example\nIt's also possible to use `+` instead of `.Do()`.\n\n```csharp\nvar model = new Asdf(\"a\");\n\nvar myString = (model.Chain()\n\t\t\t\t+ (m =\u003e m.ParameterMethod(\"b\"))\n\t\t\t\t+ (m =\u003e m.ParameterMethod(\"c\"))\n\t\t\t\t+ (m =\u003e m.ParameterMethod(\"d\", 1)))\n\t.Value()\n\t.GetMyString();\n```\n\n## Project structure\nChainly.Dotnet.sln - .NET  core project supporting multiple frameworks\nChainly.net452.sln - Old .NET 4.5.2 solution kept for compatibility\n\n## License\nThis project is licensed under the MIT license, see [LICENSE](LICENSE).\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmatsson%2Fchainly","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmatsson%2Fchainly","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmatsson%2Fchainly/lists"}