Без дополнительной информации трудно определить проблему, но основная причина заключается в том, что вы, скорее всего, скомпилировали класс против другой версии класса, у которой отсутствует метод, чем тот, который вы используете при его запуске .
Посмотрите на трассировку стека ... Если исключение появляется при вызове метода на объекте в библиотеке, вы, скорее всего, используете отдельные версии библиотеки при компиляции и запуске. Убедитесь, что у вас есть правильная версия обоих мест.
Если исключение появляется при вызове метода на объектах, созданных классами , которые вы сделали , то ваш процесс сборки кажется ошибочным. Убедитесь, что файлы классов, которые вы фактически запускаете, обновляются при компиляции.
В настоящее время нет ничего, что бы отображало C # в TypeScript. Если у вас много POCOs или вы думаете, что они могут часто меняться, вы можете создать конвертер - что-то простое по строкам ...
public class MyPoco {
public string Name { get; set; }
}
To
export class MyPoco {
public Name: string;
}
Существует также обсуждение Codeplex об автогенерации из C # .
Просто чтобы обновить содержимое, TypeLite может создавать интерфейсы TypeScript из C #:
Вот мой подход к его решению. Объявите свои классы C # с атрибутом, и будут создаваться файлы .d.ts (с использованием преобразований T4). Существует пакет на nuget , а источник доступен на github . Я все еще работаю над проектом, но поддержка довольно обширна.
TypeLite и T4TSs выше обоих выглядели хорошо, только что выбрали один, TypeLite, разветвили его, чтобы получить поддержку для
Тогда мне нужны интерфейсы C # и подумал, что пришло время испечь мою собственную вещь и написал простой скрипт T4, который просто делает то, что мне нужно. Он также включает в себя Enums. Репо не требуется, 100 строк T4.
Использование Нет библиотеки, нет NuGet, просто этот простой простой файл T4 - используйте «добавить элемент» в Visual Studio и выберите любой шаблон T4. Затем вставьте это в файл. Адаптируйте каждую строку с помощью «ACME». Для каждого класса C # добавьте строку
<#= Interface<Acme.Duck>() #>
Вопросы порядка, любой известный тип будет использоваться в интерфейсах follwing. Если вы используете только интерфейсы, расширение файла может быть .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.
typeof(ParticleKind)
в вашем Enum<T>
. Неужели это должно быть typeof(T)
? Также вам необходимо обновить bool
, чтобы быть boolean
для более поздних версий TypeScript
– Gone Coding
13 September 2016 в 11:44
const enum
s. Спасибо за пример. Это было очень близко, и я получил рабочий результат намного быстрее.
– Gone Coding
13 September 2016 в 13:45
У меня есть небольшое решение, которое использует шаблоны 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[];
}
Как насчет другого пути?
Проверьте erecruit TypeScript Translator . Он поставляется с готовой поддержкой C #, но на самом деле основан на шаблонах (использует Nunjucks для рендеринга), что означает, что он может генерировать что-нибудь еще - VB.NET, F #, C ++, XML, SQL - все, что вы можете кодировать с помощью шаблона.
Работает как консольная программа .NET, программа NodeJS (для тех, кто не находится в Windows), или как расширение Visual Studio , в комплекте с функцией генерации при сохранении. И включает поддержку MSBuild, просто чтобы сделать ваш сервер сборки счастливым. : -)
Вы также можете использовать Bridge.net. Начиная с версии 1.7, он поддерживает создание определений типа Type для типов C #. См. http://bridge.net/docs/generate-typescript-definitions/
Пожалуйста, посмотрите на эту библиотеку Typewriter
Он скрывает не только классы, перечисления, интерфейсы и т. д., но также и api-контроллеры, которые просто удивительны ..
плюс он делает, как только вы сохраняете исходный файл .cs, поэтому мне не нужно использовать какой-либо внешний инструмент для этого. Сохраните .cs, и вы получите обновление .ts
Если вам нужно создать отдельный файл для каждого сгенерированного класса / интерфейса TypeScript (т. е. в способе «один класс для каждого файла»), вы можете попробовать TypeGen . Это инструмент, который вы можете использовать из консоли диспетчера пакетов для создания файлов типа TypeScript на основе ваших классов / перечислений C #. В настоящее время он поддерживает:
плюс некоторые дополнительные функции. Это также с открытым исходным кодом (вы можете проверить это на g1] github ).
Если кто-то хочет веб-решение, я сделал простой сайт, который преобразует классы C # DTO в интерфейсы машинописного текста. http://dto2ts.ga/ (Это еще не ошибка)
Я создал небольшую утилиту, которая может генерировать интерфейсы TypeScript из классов C #. Доступно как пакет NuGet . Подробную документацию можно найти на веб-странице проекта .
Если вы используете Visual Studio, добавьте расширение Typewriter.
Обновить
С помощью Web Essentials , установленного в VS 2015, вы можете щелкнуть правой кнопкой мыши файл класса, затем> Web Essentials> Создать файл Intellisense Createcriptcript из контекстное меню.
Мое решение состояло в том, чтобы написать небольшую утилиту codegen, которая просто берет сборку проекта (и ссылается на сборки) и запускает типы сканирования, которые участвуют во взаимодействии между машинописными текстами и c #. Это использование выводит как javascript как d.ts ... Инструмент вызывается в событии после сборки ... работает как шарм!
Попытайтесь создать армию. Кажется, что он решает вашу проблему.
[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; }
}
}
%Your_Project_Directory%/Scripts/project.ts
и добавьте его в проект вручную module YourNamespace {
export interface IYourPoco
{
YourNumber: number;
YourString: string;
YourArray: string[];
YourDictionary: { [key: int]: any };
}
}
project.ts
в другом коде TypeScript. Подробнее см. в документации wiki
Если вы используете 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;
}
Вы можете использовать проект с открытым исходным кодом NSwag : в графическом интерфейсе вы можете выбрать .NET-класс из существующей .NET-библиотеки DLL и создать для него интерфейс TypeScript.
Проект также предоставляет инструменты командной строки и поддерживает шаблоны T4, а также создает клиентский код для контроллеров Web API ...
Web Essentials позволяют скомпилировать файлы C # в файлы TypeScript .d.ts
при сохранении. Затем вы можете ссылаться на определения из ваших файлов .ts
.
[/g1]
Если вы заинтересованы, вы можете использовать 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 .
]Мне нравится решение 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
Вы также можете использовать это: https://github.com/pankleks/TypeScriptBuilder
Эта небольшая библиотека генерирует определение типа TypeScript на основе типов C #. Используйте его непосредственно в своем проекте C # для создания кода для вашего проекта TypeScript с интерфейсом. Вы также можете использовать небольшое консольное приложение для генерации кода с помощью инструментов предварительной сборки.
Работает на Full & amp; NET Core Framework!
Установить по nuget: Install-Package TypeScriptBuilder
any
для типов, которые не могут быть преобразованы Подробное описание : https://github.com/pankleks/TypeScriptBuilder/blob/master/README.md
TypeScriptBuilder
, и пока он выглядит превосходно; hooray для поддержки .NET Core!
– Toby J
18 May 2017 в 15:34
Мне также очень понравился ответ @ citykid, поэтому я расширил его, чтобы сделать целое пространство имен за раз. Просто поместите классы POCO в пространство имен и перестройте шаблоны T4. Мне жаль, что я не знаю, как создавать отдельные файлы для каждого, но это не конец света.
Вам нужно ссылаться на файлы .DLL в верхней части (где вам нужны классы), и вам нужно указать пространства имен. Все строки для редактирования отмечены с помощью ACME. Познай!
<#@ 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();
}
#>
Ребята взгляните на https://github.com/reinforced/ Reinforced.Typings. Последние несколько дней я играю с шаблонами и t4-шаблонами и заканчиваю этот проект. Это супер-просто и работает как шарм. Просто получите пакет, измените файл конфигурации (это похоже на 10 секунд) и выполните сборку. Все делается автоматически без каких-либо проблем. Благословите автора!
Плохая вещь в шаблонах T4 заключается в том, что после сборки из VS отсканированные сборки блокируются, и вы должны перезапустить VS (как это глупо?). В T4 Toolbox + есть некоторые способы очистки VS, но ни один из них не работал для меня.