2014-03-30 84 views
0

如何使用约定自动从接口创建类的默认实现。换句话说,如果我有一个接口:使用字段/属性命名约定从接口自动生成类生成

public interface ISample 
{ 
    int SampleID {get; set;} 
    string SampleName {get; set;} 
} 

是否有一个片段,T4模板,或者从上面的接口自动生成下面类中的一些其他方法?正如你所看到的,我希望该字段的名称前把下划线,然后使该领域的相同的名称属性,但较低的情况下,第一个字母:

public class Sample 
{ 
    private int _sampleID; 
    public int SampleID 
    { 
      get { return _sampleID;} 
      set { _sampleID = value; } 
    } 

    private string _sampleName; 
    public string SampleName 
    { 
      get { return _sampleName;} 
      set { _sampleName = value; } 
    }  
} 

回答

1

我不知道,如果T4在可读性方面是最简单的解决方案,但您也可以使用其他代码生成工具:the CodeDom provider

这个概念非常简单:代码由构建在一起的构建块组成。

当时间成熟时,这些构建块将被解析为选择的语言。你最终得到的是一个包含你新创建的程序源代码的字符串。之后,您可以将其写入文本文件以供进一步使用。

正如您已经注意到的那样:没有编译时结果,一切都是运行时。如果你真的想要编译时,那么你应该使用T4代替。

的代码:

using System; 
using System.CodeDom; 
using System.CodeDom.Compiler; 
using System.IO; 
using System.Reflection; 
using System.Text; 

namespace TTTTTest 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      new Program(); 
     } 

     public Program() 
     { 
      // Create namespace 
      var myNs = new CodeNamespace("MyNamespace"); 
      myNs.Imports.AddRange(new[] 
      { 
       new CodeNamespaceImport("System"), 
       new CodeNamespaceImport("System.Text") 
      }); 

      // Create class 
      var myClass = new CodeTypeDeclaration("MyClass") 
      { 
       TypeAttributes = TypeAttributes.Public 
      }; 

      // Add properties to class 
      var interfaceToUse = typeof (ISample); 
      foreach (var prop in interfaceToUse.GetProperties()) 
      { 
       ImplementProperties(ref myClass, prop); 
      } 

      // Add class to namespace 
      myNs.Types.Add(myClass); 

      Console.WriteLine(GenerateCode(myNs)); 
      Console.ReadKey(); 
     } 

     private string GenerateCode(CodeNamespace ns) 
     { 
      var options = new CodeGeneratorOptions 
      { 
       BracingStyle = "C", 
       IndentString = " ", 
       BlankLinesBetweenMembers = false 
      }; 

      var sb = new StringBuilder(); 
      using (var writer = new StringWriter(sb)) 
      { 
       CodeDomProvider.CreateProvider("C#").GenerateCodeFromNamespace(ns, writer, options); 
      } 

      return sb.ToString(); 
     } 

     private void ImplementProperties(ref CodeTypeDeclaration myClass, PropertyInfo property) 
     { 
      // Add private backing field 
      var backingField = new CodeMemberField(property.PropertyType, GetBackingFieldName(property.Name)) 
      { 
       Attributes = MemberAttributes.Private 
      }; 

      // Add new property 
      var newProperty = new CodeMemberProperty 
      { 
       Attributes = MemberAttributes.Public | MemberAttributes.Final, 
       Type = new CodeTypeReference(property.PropertyType), 
       Name = property.Name 
      }; 

      // Get reference to backing field 
      var backingRef = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name); 

      // Add statement to getter 
      newProperty.GetStatements.Add(new CodeMethodReturnStatement(backingRef)); 

      // Add statement to setter 
      newProperty.SetStatements.Add(
       new CodeAssignStatement(
        new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), backingField.Name), 
        new CodePropertySetValueReferenceExpression())); 

      // Add members to class 
      myClass.Members.Add(backingField); 
      myClass.Members.Add(newProperty); 
     } 

     private string GetBackingFieldName(string name) 
     { 
      return "_" + name.Substring(0, 1).ToLower() + name.Substring(1); 
     } 
    } 

    internal interface ISample 
    { 
     int SampleID { get; set; } 
     string SampleName { get; set; } 
    } 
} 

这产生:

enter image description here

壮丽,是吗?

旁注:属性给出Attributes = MemberAttributes.Public | MemberAttributes.Final,因为省略MemberAttributes.Final将使其成为virtual

最后但并非最不重要的是:这种迷人的灵感。 Metaprogramming in .NET by Kevin Hazzard and Jason Bock, Manning Publications.