Konwerter Protobuf na C#
Wklej schemat .proto. Dostań klasy C# z auto-properties — gotowe do wrzucenia prosto do projektu, bez wtyczki protoc.
Wejście (schemat .proto)
Wyjście (C#)
Co robi to narzędzie
Masz schemat Protocol Buffers i serwis lub klienta C#, który potrzebuje pasujących DTO. Oficjalna droga to zainstalować protoc z wtyczką C# (albo wpiąć Grpc.Tools do twojego .csproj) i pozwolić MSBuildowi wygenerować klasy partial podczas builda. To działa, ale to przesada, kiedy chcesz tylko przeczytać schemat, naszkicować typy albo wkleić wiadomość w stronę Razor czy jednorazową integrację. Ten konwerter robi tę samą robotę — wklej, skopiuj, wrzuć do Types.cs.
Mapowanie typów jest z gatunku nudnych, ale poprawnych. string zostaje string (z inicjalizatorem = "", żeby projekty z nullable references nie marudziły). bool, int32, int64, uint32, uint64, float, double mapują się odpowiednio na bool, int, long, uint, ulong, float, double. bytes staje się byte[]. repeated T robi się List<T>, map<K, V> robi się Dictionary<K, V>, a znane wrappery jak google.protobuf.Timestamp wychodzą jako string (kodowanie JSON proto3 dla timestampów to RFC 3339, czyli na poziomie wire to po prostu string — szczegóły w specyfikacji JSON proto3).
Nazwy pól dostają standardową obróbkę PascalCase — order_id → OrderId, shipping_address → ShippingAddress — zgodnie z tym, co generuje oficjalna referencja protobuf C#. Wartości enumów tracą prefiks SCREAMING_SNAKE, kiedy schemat trzyma się konwencji prefiksowania każdej wartości nazwą enuma (więc ORDER_STATUS_PENDING w enum OrderStatus staje się OrderStatus.Pending). Klasy w wyjściu są płaskie — każda zagnieżdżona wiadomość jest wyniesiona na top-level, dzięki czemu możesz je rozdzielać albo przestawiać bez rozplątywania zasięgów. Konwersja dzieje się w całości w twojej przeglądarce; nic ze schematu nie idzie nigdzie dalej.
Jak tego używać
Trzy kroki. Wyjście jest gotowe do kompilacji — wklej je do pliku <code>Types.cs</code> w swoim projekcie.
Wklej swój schemat .proto
Wrzuć schemat do edytora po lewej. syntax = "proto3"; na górze jest opcjonalny. Parser radzi sobie z zagnieżdżonymi blokami message, deklaracjami enum, oneof, map<K, V>, opcjami pól oraz typowymi dyrektywami package/import/option. Importy są rozpoznawane, ale pomijane — więc jeśli schemat zależy od importowanych typów, wklej je inline.
Konwersja nazw pól dzieje się automatycznie: customer_name w .proto staje się CustomerName w C#. Nazwy klas i enumów zostają jak były (z konwencji już są w PascalCase).
Przeczytaj wyjście
Po prawej: deklaracje public class z auto-properties { get; set; } dla każdej wiadomości oraz deklaracje public enum dla każdego enuma. Linijka using System.Collections.Generic; dochodzi, kiedy schemat używa pól repeated lub map (żeby List i Dictionary się rozwiązały). Wrzuć plik do projektu, opakuj w swój namespace i gotowe.
Podłącz to
Do czystego użycia jako DTO klasy są gotowe do serializacji System.Text.Json lub Newtonsoft.Json. Do prawdziwej roboty z gRPC w C# — implementacje serwisów, streaming, deadline’y — dalej używaj Grpc.Tools do typów wire-format, a tego konwertera używaj do ręcznie pisanych wrapperów, warstw mapowania albo fixtur testowych obok wygenerowanego kodu.
Kiedy to naprawdę oszczędza czas
Szkicowanie DTO dla nowego serwisu gRPC
Startujesz z serwisem gRPC w ASP.NET Core i chcesz zobaczyć, jak wiadomości wyglądają w C#, zanim postawisz na Grpc.Tools. Wklej .proto, rzuć okiem na klasy, zdecyduj, czy nazewnictwo pól pasuje do stylu twojego zespołu, a potem porządnie wepnij codegen.
Ręcznie pisana warstwa mapowania
Twoje wygenerowane typy gRPC żyją we własnym namespace, a do warstwy domeny chcesz mieć proste DTO. Wyjście stąd daje ci czyste klasy bez metadanowego bałaganu wygenerowanego kodu — łatwe do mapowania w obie strony za pomocą AutoMapper albo własnoręcznych konwerterów.
Przegląd zmiany w schemacie Protobuf
Kolega z zespołu dodał pola do wiadomości w PR. Chcesz zobaczyć wpływ na kształt po stronie C#, nie checkoutując brancha i nie odpalając builda. Wklej nowy schemat, zrób diff z aktualnymi typami C# i zostaw konkretny komentarz w review.
Fixturki testowe i szybkie skrypty
Piszesz jednorazowy skrypt LinqPada albo aplikację konsolową, która POSTuje do gRPC-gateway. Stawianie całego toolchaina Protobufa dla 50 linii kodu testowego to przesada. Weź klasy stąd, zserializuj je do JSON-a, wyślij request i lecisz dalej.
Częste pytania
Czy mój schemat jest gdzieś wysyłany?
Nie. Parser i emitter C# działają w całości w twojej przeglądarce jako JavaScript. Otwórz DevTools i obserwuj zakładkę Network podczas wklejania — zero requestów. Przydatne, kiedy schemat zawiera wewnętrzne nazwy typów, ścieżki paczek albo cokolwiek, czego nie chcesz wysyłać do zewnętrznego serwisu.
Czy te klasy zadziałają z kodem generowanym przez Grpc.Tools?
Produkują równoważne kształty, ale nie są identyczne bajt w bajt. Grpc.Tools generuje klasy partial, rejestracje parsera, okablowanie deskryptorów i typy bazowe z Google.Protobuf.IMessage — niczego z tego tu nie ma. Do prawdziwej roboty na protokole wire gRPC — używaj Grpc.Tools. Do kodu wyłącznie z DTO (np. bramek JSON-over-HTTP, warstw mapowania, danych testowych) to wyjście wystarczy.
Dlaczego int64 i uint64 są typowane jako long i ulong, a nie string?
Bo w C# się mieszczą. W odróżnieniu od Number z JavaScript (które tracą precyzję powyżej 2^53), long w C# obsługuje cały zakres int64 natywnie, więc nie ma powodu schodzić do string. Jeśli deserializujesz JSON proto3, w którym 64-bitowe inty przychodzą jako stringi (zgodnie ze specyfikacją mapowania JSON), System.Text.Json z JsonNumberHandling.AllowReadingFromString obsłuży konwersję.
Jak radzi sobie z konwencją wartości enumów w SCREAMING_SNAKE?
Style guide Protobufa zaleca prefiksowanie każdej wartości enuma nazwą enuma w SCREAMING_SNAKE. Konwerter to wykrywa i obcina prefiks. ORDER_STATUS_UNSPECIFIED w enumie OrderStatus staje się OrderStatus.Unspecified. Jeśli twój enum nie trzyma się tej konwencji (część wartości z prefiksem, część nie), obcięcie jest pomijane, a wartości lądują w PascalCase tak jak są.
Czy obsługuje oneof?
Każde pole z oneof jest emitowane jako zwykła auto-property. Wyjście nie wymusza ograniczenia "dokładnie jedno", które implikuje oneof — język C# nie ma jeszcze natywnych discriminated unions. Jeśli potrzebujesz ostrzejszego modelowania, spójrz na biblioteki jak OneOf na NuGet albo edytuj wyjście ręcznie do klasy bazowej z podklasami.
A co z google.protobuf.Timestamp i well-known types?
Timestamp wychodzi jako string (proto3 JSON koduje timestampy jako stringi RFC 3339). Empty i Any stają się placeholderami object — popraw je na Google.Protobuf.WellKnownTypes.Any albo mocniejszy typ, jeśli twój projekt ciągnie pakiet WKT. Wyjście jest celowo bez frameworka, dzięki czemu możesz je wrzucić do dowolnego projektu C# bez wymuszania zależności NuGet.
Powiązane narzędzia
Jeśli żonglujesz Protobufem, JSON-em i C#, te dobrze do siebie pasują: