2013-07-02 58 views
1

我想問問有沒有一個庫允許在運行時生成接口實現,並具有下面所示的一些附加功能。在運行時生成接口實現

比方說,我有這樣的接口:

interface ICustomer 
{ 
    string Name {get;set;} 
    string IAddress { get;set; } 
} 

interface IAddress 
{ 
    string Street {get;set;} 
} 

我願做這樣的事情:

ICustomer customer = someLibrary.Create<ICustomer>(bool createSubObjects) 

其中Create<T>()方法將在運行時創建一個實現這樣的:

class RuntimeCustomer : NotifyPropertyChanged,ICustomer 
//NotifyPropertyChanged would be hand written class 
{ 
    string name; 
    IAddress address = new RuntimeAddress(); 
    //if createSubObjects == false then `IAddress address = null` 

    public string Name 
    { 
     get { return name; } 
     set { SetProperty(ref name, value); } 
    } 
    public IAddress Address 
    { 
     get { return address; } 
     set { SetProperty(ref address, value) } 
    } 
} 

class RuntimeAddress : NotifyPropertyChanged, IAddress 
{ 
    string street; 
    public string Street 
    { 
     get { return street; } 
     set { SetProperty(ref,street, value) } 
    } 
} 

有什麼想法嗎?

+2

也許這樣的事情http://www.castleproject.org/projects/dynamicproxy/ – jure

+0

@jure能否請你說明如何在這種情況下使用呢?我之前在Castle和LinFu上看過,但是對於這種情況 – user2542183

回答

0

也許像這樣的工作:

public T Create<T>(bool createSubObjects) 
    { 
     T MyICustomer = default(T); 
     System.Text.StringBuilder sb = new System.Text.StringBuilder(); 
     sb.Append(@" 
      using System; 
      using System.Collections.Generic; 
      using System.Linq; 

      namespace MyNameSpace 
      { 
       public class RuntimeCustomer:NotifyPropertyChanged,").Append(typeof(T).FullName).Append(@" 
       { 
        string name;").Append(createSubObjects ? @" 
        IAddress address = new RuntimeAddress(); " :@" 
        IAddress address = null;").Append(@" 

        public string Name 
        { 
         get { return name; } 
         set { SetProperty(ref name, value); } 
        } 
        public IAddress Address 
        { 
         get { return address; } 
         set { SetProperty(ref address, value) } 
        } 
       } 

       class RuntimeAddress : NotifyPropertyChanged, IAddress 
       { 
        string street; 
        public string Street 
        { 
          get { return street; } 
          set { SetProperty(ref,street, value) } 
        } 
       } 
      }"); 

     Dictionary<string, string> providerOptions = new Dictionary<string, string>(); 
     providerOptions["CompilerVersion"] = "v3.5"; //OR YOUR VERSION 
     Microsoft.CSharp.CSharpCodeProvider provider = new Microsoft.CSharp.CSharpCodeProvider(providerOptions); 

     System.CodeDom.Compiler.CompilerParameters parameters = new System.CodeDom.Compiler.CompilerParameters(); 
     parameters.GenerateExecutable = false; 
     parameters.GenerateInMemory = true; 
     parameters.IncludeDebugInformation = true; 
     parameters.ReferencedAssemblies.Add("System.dll"); 
     parameters.ReferencedAssemblies.Add(typeof(System.Linq.Enumerable).Assembly.Location); 
     parameters.ReferencedAssemblies.Add(System.Reflection.Assembly.GetCallingAssembly().Location); 
     parameters.ReferencedAssemblies.Add(System.Reflection.Assembly.GetExecutingAssembly().Location); 

     System.CodeDom.Compiler.CompilerResults results = provider.CompileAssemblyFromSource(parameters, sb.ToString()); 

     if (results.Errors.Count == 0) 
     { 
      Type generated = results.CompiledAssembly.GetType("MyNameSpace.RuntimeAddress"); 
      MyICustomer = (T)generated.GetConstructor(Type.EmptyTypes).Invoke(null); 
     } 
     else 
     { 
      //Do something 
     } 

     return MyICustomer; 
    } 
+0

感謝您的回答。我相信像這樣發佈或編譯的IL就是這樣做的,你的代碼可以很好地工作,但是這個接口在哪裏只是樣本,所以我認爲一些庫以通用的方式存在 – user2542183

+0

@ user2542183那麼你可以創建自己的庫,並使它通過將代碼文本作爲參數傳遞給create函數來更靈活。因爲某個接口的實現需要在某處定義。投票或標記爲答案:)? –

+0

哦,是的,我會最終但我希望這樣的事情已經存在 – user2542183

0

作爲替代你可以你Fody。它將完成所有這些工作,而無需發佈自己的IL。請參閱https://github.com/Fody/PropertyChanged 只需將其Nuget它並添加一個屬性到您的類,或從INotifyPropertyChanged派生。

相關問題