Як повторно використовувати існуючі визначення класу C # у проектах TypeScript


121

Я просто розпочну використовувати TypeScriptв моєму клієнтському проекті HTML, який належить до проекту MVC з уже створеною моделлю доменної структури. Я хочу, щоб мої два проекти (на стороні клієнта та на сервері) повністю розділені, оскільки над цим працюватимуть дві команди ... JSON і REST використовуються для спілкування об'єктів вперед і назад.

Звичайно, мої domainоб'єкти на стороні клієнта повинні відповідати об’єктам на стороні сервера. Раніше я зазвичай робив це вручну. Чи є можливість повторно використовувати мої визначення класів C # (особливо POJOкласів у моїй доменній моделі) для створення відповідних класів у TypeScript "?


Ні, вони абсолютно різні мови.
Ганс Пасант

6
Так, я мав на увазі POCO. Я знаю, що вони абсолютно різні мови ... але було б чудово якось уникати введення всього цього знову ... Я думаю, що на даний момент я скопіюю та вставлю свій код # та .. TypeScript ... таким чином я впевнений, що я неправильно ввів атрибут .. і допоможіть мені не запам’ятовувати. Але це явно зовсім не звучить приємно.
pabloelustondo

1
Мене також цікавить інший напрямок - від модельних класів Typescript до класів моделей C #, двонаправлених деріаріалізацією через JSON.
Джейсон Клебан

Я шукав те саме, і я щойно натрапив на цей плагін Gulp, хоча я не знаю, яка підтримка в ньому є
Luke T O'Brien

Відповіді:


54

Наразі не існує нічого, що дозволить зіставити C # на TypeScript. Якщо у вас багато POCO або ви думаєте, що вони можуть часто змінюватися, ви можете створити конвертер - щось просте за принципом ...

public class MyPoco {
    public string Name { get; set; }
}

До

export class MyPoco {
    public Name: string;
}

Існує також дискусія на Codeplex про автоматичне генерування з C # .

Щоб оновити речі, TypeLite може генерувати інтерфейси TypeScript з C #:

http://type.litesolutions.net/


Так, щось подібне це те, що я думав зробити вручну .. добре. Не впевнений, що я встиг зараз написати конвертер .. але так, це була б ідея. Дякую. Майже Microsoft це робить саме зараз, про що ми говоримо.
pabloelustondo

Ви можете зробити це будь-яким із двох способів ... Створення файлів .ts за допомогою програми EnvDTE Automation або за допомогою каталогу каталогів Mef та відображення / інтроспекції. Я віддаю перевагу другому, оскільки це не залежить від візуального.
Арек Бал

1
Я почав використовувати dart і наткнувся на ту саму проблему, як ділитися типами між c # та javascript. Я сподівався, що цю проблему вирішить Typescript, але, схоже, відповіді ще немає. Мене також трохи зіпсував компілятор saltarelle, який склав c # на javascript, дуже добре saltarelle-compiler.com
BraveNewMath

2
@DanielHarvey Енуми генеруються правильно TypeLite, ймовірно, виправлені після вашого коментаря.
pauloya

1
TypeScriptPaste перетворить C # вTypescript. У вас повинен бути компілятор Roslyn, що означає Visual Studio 2015, але він працює дуже добре. Це не на 100%, і мені довелося придумати якийсь код - перетворення foreach в циклі, написання, наприклад, мого власного класу List <T>, і вам доведеться структурувати код так, щоб він був "чистим" з лише внутрішніми структурами даних, щоб працюйте з, але це була невелика ціна, щоб заплатити за можливість змінити і протестувати код у VS, а потім "скомпілювати" його в Javascript через TypeScript.
Джон Мотт

36

Web Essentials дозволяють компілювати файли C # у файли TypeScript .d.ts. Тоді ви можете посилатися на визначення з ваших .tsфайлів.

введіть тут опис зображення


Ви, можливо, плутаєте файли .ts та c #? не вдається знайти цей варіант
Флорес

1
Але після деяких пошуків я знайшов, що ти маєш на увазі .. насправді досить корисно.
Флорес

2
Насправді це не так, я впевнений, що операція нічого не "збирає", вона генерує код. Це мене збентежило, але не на 99% вірно, я тобі дам це ;-)
Флорес

1
Це було б більш корисно, якщо ми могли налаштувати його простір імен та деякі налаштування.
Фаршид Сабері

5
Тепер ви повинні встановити "Генератор дефініції TypeScript" вручну, щоб використовувати це - дивіться тут
Таран

24

І TypeLite, і T4TS вище виглядали непогано, тільки що вибрали один, TypeLite, розпрощали його, щоб отримати підтримку

  • ValueTypes ,
  • Нульові
  • camelCasing (кореневий документ TypeScript використовує верблюдів, і це дуже добре разом із C #)
  • загальнодоступні поля (люблю чисті і читабельні POCO, також спрощує компілятор C #)
  • відключити генерацію модуля

Тоді мені були потрібні інтерфейси C # і я подумав, що настав час випекти власну річ і написав простий сценарій T4, який просто робить те, що мені потрібно. Сюди також входять Enums . Не потрібно репортажу, лише <100 рядків Т4.

Використання
Ні бібліотеки, ні NuGet, просто цей простий простий файл T4 - використовуйте "Додати елемент" у Visual Studio та виберіть будь-який шаблон T4. Потім вставте це у файл. Адаптуйте кожен рядок із написом "ACME". Для кожного класу C # додайте рядок

<#= Interface<Acme.Duck>() #>

Питання порядку, будь-який відомий тип буде використовуватися в наступних інтерфейсах. Якщо ви використовуєте тільки інтерфейси, розширення файлу може бути .d.ts , перерахування вам потрібен ts - файл, так як змінна екземпляра.

Налаштування
Злому сценарію.

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)ACME.Core.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>

<#= Interface<Acme.Bunny>() #>
<#= Interface<Acme.Duck>() #>
<#= Interface<Acme.Birdy>() #>
<#= Enums<Acme.CarrotGrade>() #>
<#= Interface<Acme.LinkParticle>() #>

<#+  
    List<Type> knownTypes = new List<Type>();

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "bool";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

Наступним рівнем сценарію буде створення сервісного інтерфейсу з класу MVC JsonController.


1
Дуже мило, але ти маєш typeof(ParticleKind)у своєму Enum<T>. Напевно, це має бути typeof(T)? Також вам потрібно оновити, boolщоб бути booleanна наступні версії TypeScript
Пройшло кодування

Також зверніть увагу: це розриває властивості enum у класах
Gone Coding

1. Ага, так, дякую за голову вгору, це виправить. 2. Машинопис написав цей текст із часу написання цього сценарію. Схоже, це може потребувати деяких оновлень, ви, звичайно, праві. Я сподіваюся, що це послужить відправною точкою для ваших власних цілей.
citykid

1
Я перетворив його в бібліотеку-помічник, виправляв помилки і тепер використовую лише однорядкові записи у своїх TT-файлах для створення інтерфейсів та нових const enums. Дякую за приклад. Це було дуже близько і отримало мені робочий результат набагато швидше.
Пройшов кодування

24

Якщо ви використовуєте vscode, ви можете використовувати моє розширення csharp2ts, яке робить саме це.

Ви просто вибираєте вставлений код C # і запускаєте Convert C# to TypeScriptкоманду з палітри команд введіть тут опис зображення Приклад перетворення:

public class Person
{
    /// <summary>
    /// Primary key
    /// </summary>
    public int Id { get; set; }

    /// <summary>
    /// Person name
    /// </summary>
    public string Name { get; set; }
}

до

export interface Person
{
    /**Primary key */
    Id : number;

    /**Person name */
    Name : string;
}

1
Я думаю, що людей цікавить повністю автоматизоване рішення, коли компіляція з msbuild видає визначення машинопису до їх вживання. Чи є спосіб отримати це за допомогою плагіна?
бінкі

Ні, це плагін VSCode, працює лише всередині редактора, а не як окрема програма
Рафаель,

Я перетворив це розширення vscode в модуль вузла, якщо ви хочете через node.js або tytpescript. Перевірити репо можна тут: github.com/YuvrajSagarRana/csharp-to-typescript
Sagar Rana

Чи є спосіб зв’язати команду з комбінацією клавіш? Наприклад, вибрав би .net-код, маючи налаштування shift + ctrl + c, щоб виконати "Перетворити C # в TypeScript", це пришвидшило б процес. Мені подобається плагін!
Pawel Cioch

18

Ось мій підхід до її вирішення. Задекларуйте свої C # класи з атрибутом і будуть створені .d.ts-файли (з використанням перетворень T4). Є пакунок на nuget, а джерело доступне на github . Я все ще працюю над проектом, але підтримка досить велика.


Я відправив цей проект і додав підтримку нокауту тут: github.com/omniscient/t4ts
Frank.Germain

18

Якщо ви використовуєте Visual Studio, додайте розширення "Друкарська машинка".

Галерея Visual Studio

Веб-сайт / Документація

Оновлення

За допомогою програми Web Essentials, встановленої у VS 2015, ви можете клацнути правою кнопкою миші файл класу, а потім> Веб-основи> Створити файл текстового сценарію Intellisense у контекстному меню.


Він створив файл d.ts для підтримки intellisense, але як він використовує його, а потім, яке відношення до створення базових класів? Я зайшов до WebEssentails і не можу знайти жодного документа. Будь-які пропозиції? ТІА.
howardlo

@hio Просто посилайтеся на файл d.ts у будь-якому файлі .ts, у якому вам потрібно використовувати його. Коли / якщо ви зміните свій клас, базовий файл d.ts оновиться. (Порада: Ви можете перетягнути d.ts файл в верхній частині .ts файл , і він буде створювати посилання для вас).
Michael Tranchida

Дякую Майклу! Я спробував перенести файл d.ts у порожній .ts файл, і він лише додав файл до папки, що містить. Спробував це у VS2015 та новому VS2017, такі ж результати. Чи знаєте ви якесь відео чи підручник, який показує, як це все працює? TIA
howardlo

Я спробував скинути файл d.ts у файл .ts у редакторі, і він створив посилання. Я думаю, що зараз розумію. Підручник все ще вітається. Дякую!
howardlo

@hlo Вибачте, не знаю жодних навчальних посібників. Коли я йду маршрутом Web Essentials, я робив дублікати файлів .ts, оскільки мої доменні моделі знаходяться в бібліотеці класів, і в моєму клієнтському коді мені зазвичай потрібно створити моделі dto або vm, для яких потрібен браузер. знати про. Якщо у вас виникли проблеми з усім цим, спробуйте розширення Typewriter. Це дозволяє мати файли моделей ur .ts у будь-якому місці.
Майкл Транчіда

15

Спробуйте рамку Reinforced.Typings. Здається, це вирішує вашу проблему.

  1. Встановіть його з NuGet
  2. Перейдіть до свого POCO та додайте [TsInterface]над ним атрибут

    using Reinforced.Typings.Attributes;
    namespace YourNamespace {
        [TsInterface]
        public class YourPoco
        {
            public int YourNumber { get;set; }
            public string YourString { get;set; }
            public List<string> YourArray { get;set; }
            public Dictionary<int, object> YourDictionary { get;set; }
        }
    }
  3. Побудуйте свій проект
  4. Дізнайтеся згенерований код TypeScript у %Your_Project_Directory%/Scripts/project.tsфайлі та додайте його до проекту вручну

    module YourNamespace {
        export interface IYourPoco
        {
            YourNumber: number;
            YourString: string;
            YourArray: string[];
            YourDictionary: { [key: int]: any };
        }
    }
  5. Зробіть те ж саме для всіх своїх POCO та посилань project.tsу іншому коді TypeScript.

Детальніше див. У вікі документації


Додайте фрагмент зразка, а лише
поділіться


Але добре, я наведу приклад тут :)
Павло Б. Новіков

Ні. Підтримка .NET Core ( посилання ) :(
Алекс Клаус

5
Підтримка @AlexKlaus .NET Core прибула
Новіков Павло Б.

10

Я створив невелику утиліту, яка може генерувати інтерфейси TypeScript з класів C #. Доступний як пакет NuGet . Детальну документацію можна знайти на веб-сторінці проекту .


Гарна бібліотека, добрі зусилля. На жаль, не знайдено способу налаштувати створений тип значення, наприклад, перетворити "рядок" в "KnockoutObservableString" або "string []" в "KnockoutObservableArray". Це щось, що є в найближчих планах на майбутнє?
корінь

2
Я використовував T4TS замість цього, це зайняло 14 хвилин.
корінь

@root, ви не повинні насправді перетворювати рядок [] в KnockoutObservableArray в створених визначеннях. Ви використовуєте ці згенеровані визначення, коли ви фактично споживаєте серіалізовані екземпляри цих класів. Тепер ви, можливо, запускаєте весь об’єкт через плагін для картографування, але я застережу проти цього. Це може бути надмірним, і я завжди віддаю перевагу вручну конвертувати (можливо, через ctor) з ваших серіалізованих примірників класів C # в класи TypeScript, повні спостережуваних даних. Єдиний раз, коли я б запропонував сліпо запустити його через плагін відображення, це додаток для стилю CRUD.
Аллен Райс

@Lukas Kabrt, дуже дякую за TypeLite, це було надзвичайно корисно в наших проектах, і я про це коротко писав тут: underwatergorilladome.com/…
Аллен Райс

@AllenRice, я вважаю, що було зручно мати класичні класи для перегляду Knockout з переглядом, і саме тут я використовую підхід, який ви описали, і поєдную його з автоматично сформованим класом, який є DTO, переданим через плагін для картографування.
корінь

7

Погляньте на цю машинку бібліотеки

Він перетворює не тільки класи, перерахунки, інтерфейси тощо, але й api-контролери, що просто приголомшливо.

Плюс це робиться так, як тільки ви зберігаєте вихідний файл .cs, тому мені не потрібно запускати жоден зовнішній інструмент. Збережіть .cs і ви отримаєте оновлення .ts


Чудова річ у тому, що він створює TS-файли при збереженні відповідних CS-файлів. Однак налаштування вихідної папки досить крихке (див. Обговорення тут ) і вимагає певного коду, виготовленого вручну.
Олексій Клаус

Я використовую інструменти для збирання для цього, і цей інструмент є набагато потужнішим, ніж більшість згаданих тут
harishr

6

У мене є невелике рішення, яке використовує шаблони T4 ( переглянути джерело ).

Ви переходите з будь-якого CLR POCO:

public class Parent : Person
{
    public string Name { get; set; }
    public bool? IsGoodParent { get; set; }
    public virtual ICollection<Child> Children { get; set; }
}

Для інтерфейсу TypeScript:

///<reference path="Child.d.ts" />
///<reference path="Person.d.ts" />
interface Parent extends Person {
    Name : string;
    IsGoodParent? : bool;
    Children : Child[];
}

3

Ви можете використовувати проект з відкритим кодом NSwag : У графічному інтерфейсі ви можете вибрати .NET-клас із існуючої .NET DLL та створити для нього інтерфейс TypeScript.

Проект також пропонує інструменти командного рядка та підтримку шаблонів T4, а також генерацію коду клієнта для контролерів Web API ...


Будьте в курсі, що NSwag генерує TS-файли лише з двійкових файлів (також потрібні всі залежності ваших бінарних файлів) або з його JSON-файлу, який Swagger виробляє з двійкових файлів.
Алекс Клаус

3

Якщо вам потрібно створити окремий файл для кожного згенерованого класу / інтерфейсу TypeScript (тобто способом "один клас на файл"), ви можете спробувати TypeGen . Це інструмент, який ви можете використовувати з консолі диспетчера пакунків для створення файлів TypeScript на основі ваших класів / переліків C #. В даний час він підтримує:

  • експортування переписок; експорт POCO в якості класів TS або інтерфейсів
  • спадкування
  • родові типи
  • колекції / вкладені типи колекцій

плюс деякі додаткові функції. Це також відкритий код (ви можете перевірити це на github ).


2

Як щодо іншого?

Ознайомтеся з перекладачем TypeScript erekruit . Він постачається з готовою підтримкою C #, але насправді на основі шаблонів (використовує Nunjucks для візуалізації), а це означає, що він може генерувати будь-що інше - VB.NET, F #, C ++, XML, SQL - все, що можна кодувати за допомогою шаблону.

Працює як програма консолі .NET, програма NodeJS (для тих, хто не знаходиться в Windows), або як розширення Visual Studio , доповнене функцією генерування-збереження. І включає підтримку MSBuild, просто щоб зробити ваш сервер побудови щасливим. :-)


Я поставив це +1, тому що це дійсно найкраще рішення, генеруючи на економії функцію вбивці.
Іван Заброський

2

Ви також можете скористатися цим: https://github.com/pankleks/TypeScriptBuilder

Ця невелика бібліотека генерує визначення типу TypeScript на основі типів C #. Використовуйте його безпосередньо у своєму проекті C # для створення вихідного коду для створення коду для вашого проекту TypeFrontend. Ви також можете додавати невеликий додаток консолі, щоб генерувати код за допомогою інструментів попереднього збирання.

Працює над основними рамками Full & NET!

Встановити за допомогою nuget: Install-Package TypeScriptBuilder

Підтримувані функції

  • Вирішення залежності типу
  • Дженріки
  • Тип успадкування
  • Простори імен (модулі)
  • Перелічує
  • Зменшувані типи
  • Конверсія словника (для індексованих об'єктів сильного типу TS)
  • Набір атрибутів управління генерацією коду
  • any для типів, які неможливо перетворити

Детальний опис: https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md


Щойно спробував, TypeScriptBuilderі це виглядає чудово поки що; Ура для підтримки .NET Core!
Tobias J

1

Хлопці дивляться на https://github.com/reinforced/ Reinforced.Typings . Я грав з шаблонами typelite та t4 останні кілька днів і закінчив цей проект. Це супер просто і працює як шарм. Просто дістаньте пакет, змініть файл конфігурації (він схожий на 10 секунд) та складіть. Все відбувається автоматично, без проблем. Благословіть автора!

Погано в шаблонах T4 полягає в тому, що після створення з VS відскановані збірки заблоковані, і ви повинні перезапустити VS (наскільки це нерозумно?). У T4 Toolbox + деякі директиви щодо очищення VS є деякі шляхи, але жодна з них не працювала для мене.


1

Мені подобається рішення citykid. Я трохи подовжив його. Отже, рішення також базується на техніці генерації коду з шаблонами T4.

Він може генерувати загальні типи TypeScript і зовнішні декларації.

Він підтримує успадкування та реалізацію інтерфейсу.

Підтримує дженерики, масиви та списки як поля типів.

Крім того, він перекладається на типи TypeScript, які в конфігурації не згадуються явно (наприклад, ми імпортуємо тип A, а у виводі TS можна знайти деякі інші типи: типи полів, базові типи та інтерфейси).

Ви також можете змінити назву типу.

Енуми також підтримуються.

Приклад використання (ви можете знайти його у сховищі проектів):

// set extension of the generated TS file
<#@ output extension=".d.ts" #>

// choose the type of TS import TsMode.Ambient || TsMode.Class
<# var tsBuilder = new TsBuilder(TsMode.Ambient); #>

// reference assembly with the c# types to be transformed
<#@ assembly name="$(SolutionDir)artifacts\...\CsT4Ts.Tests.dll" #>

// reference namespaces
<#@ import namespace="CsT4Ts.Tests" #>
<#
    //add types to processing
    tsBuilder.ConsiderType(typeof(PresetDTOBase), "PresetBase");
    tsBuilder.ConsiderType(typeof(PresetDTO), "Preset");
    tsBuilder.ConsiderType(typeof(TestInterface<,>));
#>

// include file with transformation algorithms
<#@ include file="CsT4Ts.t4" #>

І ви отримаєте вихід

//CsT4Ts.Tests.PresetDTOBase => PresetBase
// CsT4Ts.Tests.PresetDTO => Preset
// CsT4Ts.Tests.TestInterface`2 => TestInterface
// CsT4Ts.Tests.TestEnum => TestEnum

declare class PresetBase
{
    PresetId: string;
    Title: string;
    InterviewDate: string;
}

declare class Preset extends PresetBase
{
    QuestionsIds: string[];
}

declare interface TestInterface<TA, TB>
{
    A: string;
    B: number;
    C: TestEnum;
    D: TestEnum[];
    E: number[];
    F: TA;
    G: TB[];
}

declare enum TestEnum
{
    Foo = 10,
    Boo = 100
}

Перевірте повне рішення тут: https://bitbucket.org/chandrush/cst4ts


1

Ви також можете використовувати Bridge.net. З версії 1.7 він підтримує генерацію визначення TypeScript для типів C #. Дивіться http://bridge.net/docs/generate-typescript-definitions/


Основна проблема полягає в тому, що під час пошуку в Google ви можете скористатися оригінальним запитанням і ніколи не помітите, що корисна інформація існувала при повторенні / закритій відповіді
Джордж Бірбіліс

Тому переконайтеся, що у каноніку є найкраща інформація. Не публікуйте багато запитань. Будь-яку подальшу дискусію з цього приводу можна взяти у Meta Stack Overflow
Martijn Pieters

1

Також мені дуже сподобалась відповідь @ citykid, тому я розширив її, щоб створити цілий простір імен за один раз. Просто помістіть класи POCO у простір імен та переобладнайте шаблони T4. Я б хотів, щоб я знав, як генерувати окремі файли для кожного, але це не кінець світу.

Вам потрібно посилатись на файли .DLL у верхній частині (де потрібні класи), і вам потрібно згадати простори імен. Усі рядки для редагування позначені ACME. Основні cudos на @citykid, оцініть це!

<#@ template debug="true" hostSpecific="true" language="C#" #>
<#@ output extension=".ts" #>
<#@ Assembly Name="System.Core.dll" #>
<#@ assembly name="$(TargetDir)YOUR_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ assembly name="$(TargetDir)YOUR_OTHER_DLL_NAME_HERE_ACME.dll" #>
<#@ import namespace="System" #>
<#@ import namespace="System.Reflection" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Reflection" #>

<#= Process("My.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>
<#= Process("My.Other.Very.Special.Namespace.ACME") #>

<#+  

    List<Type> knownTypes = new List<Type>();

    string Process(string nameSpace) {
      var allass = AppDomain.CurrentDomain.GetAssemblies();
      var ss = "";
      foreach (var ass in allass)
      {
         ss += ProcessAssembly(ass, nameSpace);
      }
      return ss;
    }

   string ProcessAssembly(Assembly asm, string nameSpace) {
      try {
            Type[] types;
            try
            {
                types = asm.GetTypes();
            }
            catch (ReflectionTypeLoadException e)
            {
                types = e.Types;
            }
            var s = "";
            foreach (var t in types.Where(t => t != null))
            {
               try {

               if (String.Equals(t.Namespace, nameSpace, StringComparison.Ordinal))
               {
                    s += InterfaceOfType(t);
               }

               } catch (Exception e)
               {
               }
            }
            return s;      
      }
      catch (Exception ee2) {
        return "// ERROR LOADING TYPES: " + ee2;
      }

   }

    string InterfaceOfType(Type T)
    {   
        Type t = T;     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\r\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    string Interface<T>()
    {   
        Type t = typeof(T);     
        var sb = new StringBuilder();
        sb.AppendFormat("interface {0} {{\n", t.Name);
        foreach (var mi in GetInterfaceMembers(t))
        {
            sb.AppendFormat("  {0}: {1};\r\n", this.ToCamelCase(mi.Name), GetTypeName(mi));
        }
        sb.AppendLine("}");
        knownTypes.Add(t);
        return sb.ToString();
    }

    IEnumerable<MemberInfo> GetInterfaceMembers(Type type)
    {
        return type.GetMembers(BindingFlags.Public | BindingFlags.Instance)
            .Where(mi => mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property);
    }

    string ToCamelCase(string s)
    {
        if (string.IsNullOrEmpty(s)) return s;
        if (s.Length < 2) return s.ToLowerInvariant();
        return char.ToLowerInvariant(s[0]) + s.Substring(1);
    }

    string GetTypeName(MemberInfo mi)
    {
        Type t = (mi is PropertyInfo) ? ((PropertyInfo)mi).PropertyType : ((FieldInfo)mi).FieldType;
        return this.GetTypeName(t);
    }

    string GetTypeName(Type t)
    {
        if(t.IsPrimitive)
        {
            if (t == typeof(bool)) return "boolean";
            if (t == typeof(char)) return "string";
            return "number";
        }
        if (t == typeof(decimal)) return "number";            
        if (t == typeof(string)) return "string";
        if (t.IsArray)
        {            
            var at = t.GetElementType();
            return this.GetTypeName(at) + "[]";
        }
        if(typeof (System.Collections.IEnumerable).IsAssignableFrom(t)) 
        {
            var collectionType = t.GetGenericArguments()[0]; // all my enumerables are typed, so there is a generic argument
            return GetTypeName(collectionType) + "[]";
        }            
        if (Nullable.GetUnderlyingType(t) != null)
        {
            return this.GetTypeName(Nullable.GetUnderlyingType(t));
        }
        if(t.IsEnum) return "number";
        if(knownTypes.Contains(t)) return t.Name;
        return "any";
    }

    string Enums<T>() // Enums<>, since Enum<> is not allowed.
    {
        Type t = typeof(T);        
        var sb = new StringBuilder();        
        int[] values = (int[])Enum.GetValues(t);
        sb.AppendLine("var " + t.Name + " = {");
        foreach(var val in values) 
        {
            var name = Enum.GetName(typeof(T), val);
            sb.AppendFormat("{0}: {1},\r\n", name, val);
        }
        sb.AppendLine("}");
        return sb.ToString();
    }
#>

0

Моє рішення полягало в тому, щоб написати невелику утиліту кодегена, яка просто займається складанням проектів (і повторним оновленням збірок) та починає сканувати типи, які беруть участь у взаємодії між typecript та c #. Ця утиліта виводить як JavaScript як d.ts ... Інструмент викликається у події після збирання ... працює як шарм!


Я не знаю, чому я вирішив вивести js і d.ts ... зараз він просто виводить .ts ... прямо і дуже виконано.
Paul0515

1
Привіт Пол, чи зможеш ти поділитися з нами кодом утиліти. Я хочу просто створити файл ts (у певному місці папки), а не файл d.ts, як ви сказали. Це те, що може зробити ваш утиліт ??
Кришна Тея Верачачанені

0

Якщо вам цікаво, ви можете використовувати TypedRpc . Її мета полягає не лише у створенні інтерфейсів у TypeScript, але і у всьому зв'язку з сервісом у .Net за допомогою протоколу JsonRpc.

Приклад для класу на сервері:

[TypedRpc.TypedRpcHandler]
public class RpcServerExample
{
    public String HelloWorld()
    {
        return "Hello World!";
    }
}

Використання створеного коду TypeScript:

/// <reference path="Scripts/TypedRpc.ts" />

let rpc: TypedRpc.RpcServerExample = new TypedRpc.RpcServerExample();

var callback = function(data, jsonResponse) {
    console.log(data);
};

rpc.HelloWorld().done(callback).fail(callback);

Перегляньте на https://github.com/Rodris/TypedRpc інші приклади, як ним користуватися.


0

Генератори клієнтів веб-API ASP.NET можуть бути зручнішими, меншими накладними, ніж шахрайські інструментальні ланцюги та інші під час SDLC.

Хоча програмісти, як правило, використовують WebApiClientGen для генерування кодів клієнтського API, цей проект також пропонує POCO2TS.exe, програму командного рядка, яка генерує інтерфейси TypsScript з класів POCO. Ви можете використовувати або Poco2ts.exe, або компонент poco2ts, щоб інтегрувати генерацію коду в конвеєр побудови.


0

Якщо ви хочете перетворити його через node.js, ви можете використовувати цей пакет (csharp-to-typecript). https://www.npmjs.com/package/csharp-to-typescript

кислотний код: https://github.com/YuvrajSagarRana/csharp-to-typescript

eg: 
// After installation, import the package.
var { CsharpToTs, getConfiguration } = require("csharp-to-typescript");

// Use CsharpToTs to convert your source code a. Method one give your source code as string:
const sourceCodeInString =   `public class Address
{
  public int Id {get; set;}
  public string Street { get; set; }
  public string City { get; set; }
}`

var outputTypescript = CsharpToTs(sourceCodeInString, getConfiguration());
console.log(outputTypescript);

// Output is

export class Address
{
  Id: number;
  Street: string;
  City: string;
}

0

Якщо ви використовуєте VSCode, ви можете подивитися на це розширення C # на TypeScript

Перетворити клас C # в інтерфейс TypeScript

Подивіться, як я можу конвертувати його з коду C # лише в один клік. Звичайно, не всі класи будуть перетворені, такі як завод, але це досить добре для клієнта. Нам просто потрібна форма даних. Іноді Якщо мені потрібно використовувати шаблон відвідувача, я прикрашу додаткові методи, які мені потрібні. На це пішло лише 5 секунд. Порівнюючи хвилину вище, я можу сказати, що це велика перемога.

Детальніше дивіться у моїй публікації в блозі

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.