【问题标题】:Generating interface implementation at runtime在运行时生成接口实现
【发布时间】:2013-07-03 01:31:08
【问题描述】:

我想问一下是否有一个库允许在运行时生成接口的实现,并具有如下所示的一些附加功能。

假设我有这样的界面:

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

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

我想做这样的事情:

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

Create&lt;T&gt;() 方法会在运行时创建这样的实现:

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) }
    }
}

有什么想法吗?

【问题讨论】:

标签: c# mvvm castle-windsor interceptor proxy-classes


【解决方案1】:

正如 jure 所说,您可以为此使用 DynamicProxy,但这将是应用于 JIT 接口实现的方面。看看这个:http://jonas.follesoe.no/2009/12/23/automatic-inotifypropertychanged-using-dynamic-proxy/

PostSharp 在这个用例上也表现出色,但它是通过编译时编织与运行时 JIT'ing 来完成的。 http://www.postsharp.net/aspects/examples/inotifypropertychanged

希望对你有帮助

【讨论】:

    【解决方案2】:

    也许这样的事情会起作用:

    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; 
        }
    

    【讨论】:

    • 感谢您的回答。我相信 IL 发射或编译是必须这样做的,你的代码可以很好地工作,但是这个接口只是样本,所以我认为存在一些以通用方式这样做的库
    • @user2542183 好吧,您可以创建自己的库,并通过将代码文本作为参数传递给 create 函数来使其更加灵活。因为必须在某个地方定义某个接口的实现。投票或标记为答案:)?
    • 哦,是的,我最终会的,但我希望这样的东西已经存在
    【解决方案3】:

    作为替代方案,你可以 Fody。它将完成所有这些以及更多操作,而无需发出您自己的 IL。见https://github.com/Fody/PropertyChanged 只需 Nuget 它并向您的类添加一个属性,或从 INotifyPropertyChanged 派生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-13
      • 1970-01-01
      • 1970-01-01
      • 2011-03-27
      • 2011-07-03
      • 2014-07-09
      相关资源
      最近更新 更多