TypeLite et T4Ts au-dessus des deux avait l'air bien, juste pris un, TypeLite, fourche à obtenir un soutien pour
-
ValueTypes,
- Nullable
-
camelCasing (Tapuscrit racine doc utilise des chameaux, et cela va trop bien ensemble avec le C#)
-
champs publics (l'amour propre et lisible POCOs, le rend aussi facile pour le Compilateur C#)
- désactiver le module de génération
Ensuite, j'ai besoin de C# interfaces et de la pensée, il est temps d'écrire un simple T4 script qui fait exactement ce dont j'ai besoin. Il comprend également des Enums. Pas de pensions de titres requis, il suffit de < 100 lignes de T4.
L'utilisation de la
Pas de bibliothèque, pas de NuGet, juste cette plaine simple fichier T4 - utilisation "ajouter un élément" dans Visual Studio et choisir n'importe quel modèle T4. Puis les coller dans le fichier. S'adapter à chaque ligne avec "ACME". Pour chaque classe C# ajouter une ligne
<#= Interface<Acme.Duck>() #>
L'ordre des questions, de tout type connu sera utilisé dans les interfaces suivantes. Si vous utilisez uniquement des interfaces, de l'extension de fichier peut être .d.ts, pour les énumérations, vous avez besoin d'un .ts fichier, depuis une variable est instanciée.
Personnalisation
Hack le script.
<#@ 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 ParticleKind = {");
foreach(var val in values)
{
var name = Enum.GetName(typeof(ParticleKind), val);
sb.AppendFormat("{0}: {1},\n", name, val);
}
sb.AppendLine("}");
return sb.ToString();
}
#>
Le prochain niveau du script sera de créer l'interface de service de la MVC JsonController classe.