{"id":27128409,"url":"https://github.com/akronae/proteus","last_synced_at":"2025-10-12T19:44:48.852Z","repository":{"id":137527189,"uuid":"200877461","full_name":"Akronae/Proteus","owner":"Akronae","description":"Reflection-based and efficient serializer for .NET and Unity. 🔁","archived":false,"fork":false,"pushed_at":"2021-03-11T13:04:56.000Z","size":170,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-30T14:55:35.623Z","etag":null,"topics":[],"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/Akronae.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,"zenodo":null}},"created_at":"2019-08-06T15:23:52.000Z","updated_at":"2021-03-11T13:04:58.000Z","dependencies_parsed_at":null,"dependency_job_id":"f366c97e-6cc0-4c8f-bf9d-43e08e98413f","html_url":"https://github.com/Akronae/Proteus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Akronae/Proteus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akronae%2FProteus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akronae%2FProteus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akronae%2FProteus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akronae%2FProteus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Akronae","download_url":"https://codeload.github.com/Akronae/Proteus/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Akronae%2FProteus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279012680,"owners_count":26085159,"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","status":"online","status_checked_at":"2025-10-12T02:00:06.719Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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-04-07T18:57:56.398Z","updated_at":"2025-10-12T19:44:48.846Z","avatar_url":"https://github.com/Akronae.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Modern cross-platform serializer designed for simplicity and scalability\n\n![Hello World](http://1.bp.blogspot.com/_dg0YrAzykYY/TQxf30endCI/AAAAAAAAAAw/wdk0ql7g1qo/s1600/p.jpeg)\n\nProteus is a reflection-based serializer that I use for my projects.\n\n# [Download the NuGet package](https://github.com/Akronae/Proteus/tree/master/nuget)\n\n# Documentation\n## Basic serialization\n```cs\nvar serializer = new Serializer();\n\n// Let's say we have this class:\nclass Person\n{\n    // SerializedMember tells the serializer which member must be serialized and in which order.\n    [SerializedMember(0)]\n    public int Age;\n    [SerializedMember(1)]\n    public string Name;\n    [SerializedMember(2)]\n    public bool Female;\n    \n    public override string ToString ()\n    {\n        return $\"{nameof(Person)} {Age} {Name} {(Female ? 'F' : 'M')}\";\n    }\n}\n\nvar serialized = serializer.Serialize(new Person {Age = 20, Female = false, Name = \"Doe\"});\nConsole.WriteLine(BitConverter.ToString(serialized)); // Prints: \"01-00-14-01-03-00-00-00-44-6F-65-01-00\".\n\nvar deserialized = Serializer.Deserialize\u003cPerson\u003e(serialized)\nConsole.WriteLine(deserialized); // Prints: \"Person 20 Doe M\".\n```\n\n## Inheritance\n```cs\n// Let's say we have the following classes.\nclass Person\n{\n    [SerializedMember(0)]\n    public int Age;\n    [SerializedMember(1)]\n    public string Name;\n    [SerializedMember(2)]\n    public bool Female;\n\n    public override string ToString ()\n    {\n        return $\"{nameof(Person)} {Age} {Name} {(Female ? 'F' : 'M')}\";\n    }\n}\n\nclass Employee : Person\n{\n    // Note that you don't need to be aware of the last serialized member's index of the base class,\n    // they are class-specific and their absolute value don't matter,\n    // only the relative order of the indexes does.\n    [SerializedMember(0)]\n    public int Wage;\n    [SerializedMember(1)]\n    public Vector2 DeskLocation;\n}\n\nclass Vector2\n{\n    [SerializedMember(0)]\n    public int X;\n    [SerializedMember(1)]\n    public int Y;\n\n    public Vector2 (int x, int y)\n    {\n        X = x;\n        Y = y;\n    }\n    \n    // When a class has a constructor it must also have a parameterless constructor as the serializer\n    // uses parameterless constructor to create instances.\n    public Vector2 ()\n    {\n    }\n\n    public override string ToString ()\n    {\n        return $\"({X}, {Y})\";\n    }\n}\n\nvar serializer = new Serializer();\nvar person = new Employee {Age = 20, Female = false, Name = \"Doe\", Wage = 3500,\n                           DeskLocation = new Vector2(50, 12)};\nvar serialized = serializer.Serialize(person);\nvar deserialized = serializer.Deserialize\u003cEmployee\u003e(serialized);\n\nConsole.WriteLine(deserialized); // Prints \"20 Doe M 3500 (50, 12)\".\n```\n\n## Generic\n```cs\n// Let's say we have these classes\nclass Person\n{\n    [SerializedMember(0)]\n    public int Age;\n    [SerializedMember(1)]\n    public string Name;\n\n    public override string ToString ()\n    {\n        return $\"{Age} {Name}\";\n    }\n}\n\nclass Employee : Person\n{\n    [SerializedMember(0)]\n    public int Wage;\n    public override string ToString ()\n    {\n        return base.ToString() + $\" {Wage}\";\n    }\n}\n\n// We want to serialize then deserialize a list of Person\nvar serializer = new Serializer();\nvar persons = new List\u003cPerson\u003e() {new Employee {Age = 21, Name = \"Doe\", Wage = 3400},\n                                  new Person{Age = 29, Name = \"John\"}};\nvar serialized = serializer.Serialize(persons);\nvar deserialized = serializer.Deserialize\u003cList\u003cPerson\u003e\u003e(serialized);\n\nforeach (var person in deserialized)\n{\n    Console.WriteLine(person); // Prints: \"21 Doe \\n 29 John\".\n}\n\n// Now, if we want to be able to serialize a List of several inherited classes, we could do so:\n\n// `LoadedAssembliesGenericTypesProvider` will scan all the assemblies\n//  and tell the serializer each Type generic ID.\nvar serializer = new Serializer(new LoadedAssembliesGenericTypesProvider());\n\n// We have to give a unique ID to the class Employee (here 10) with the SerializableAsGeneric attribute.\n[SerializableAsGeneric(10)]\nclass Employee : Person\n{\n    [SerializedMember(0)]\n    public int Wage;\n    public override string ToString ()\n    {\n        return base.ToString() + $\" {Wage}\";\n    }\n}\n\n// ...\nforeach (var person in deserialized)\n{\n    Console.WriteLine(person); // Prints: \"21 Doe 3400 \\n 29 John\".\n}\n```\n\nHere `new LoadedAssembliesGenericTypesProvider()` given to the serializer scans all the loaded assemblies for `SerializableAsGeneric` and stores the types, but a custom generic type provider which inherits [IGenericTypesProvider](https://github.com/Akronae/Proteus/blob/master/Proteus.Core/IGenericTypesProvider.cs) can be used instead.\n\n**This works everywhere (not only for `List\u003c\u003e`) as long as the class deserialized has a `SerializableAsGeneric` attribute for \nthe serializer to retrieve the class structure during deserialization.**\n\n## Data architecture\nHere are the supported native types:  \n* Boolean\n* Byte\n* Int16 (short)\n* Char\n* Int32 (int)\n* Single (float)\n* String\n* Enum\n* Guid\n* List\u003c\u003e\n* Dictionary\u003c,\u003e\n\nNested classes are serialized as well.  \nYou don't need to worry about the space that a number takes, Proteus will figure out automatically how to encode it.  \nFor instance:\n```cs\nserializer.Serialize(1); // 01-FF-00-00-01\n```\nThe first byte `01` means that the number following is encoding as `SByte` see [NumberType.cs](https://github.com/Akronae/Proteus/blob/master/Proteus.Core/NumberType.cs)).  \nThe second byte `FF = -1.` is the generic type ID of the following serialized object, \nhere there is none (`-1 = unedefined generic type`).\nThe third byte `00` is a flag set on every member, it tells weather or not the value is null,\n`00 = value is not null`, `01 = value is null`.  \nthe fourth byte `00` means the the number is encoded as a `Byte`.\nThe fifth byte `01 = 1.`.\n\nProteus is designed this way to be reliable, you don't have to worry about the space numbers could take and to save space as most of the time the space allocated to numbers is way bigger than the numbers really need, so the byte used to tell the number encoding is largely compensated.\n\n**_Summup: Always use either int or float as value type for number fields._**\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakronae%2Fproteus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fakronae%2Fproteus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fakronae%2Fproteus/lists"}