Генерация реализации интерфейса во время выполнения

Я хотел бы спросить, есть ли библиотека, которая позволяет генерировать реализацию интерфейса во время выполнения с некоторыми дополнительными функциями, показанными ниже.

Допустим, у меня есть такой интерфейс:

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

Любая идея, пожалуйста?


person user2542183    schedule 02.07.2013    source источник
comment
может быть что-то вроде этого castleproject.org/projects/dynamicproxy   -  person Jurica Smircic    schedule 02.07.2013
comment
@jure, не могли бы вы проиллюстрировать, как его использовать в этом случае? Раньше я искал Castle и LinFu, но не нашел их полезными для этого случая.   -  person user2542183    schedule 02.07.2013


Ответы (3)


как сказал Юре, вы можете использовать DynamicProxy для этого, но это будут аспекты, применяемые к JIT-реализации ваших интерфейсов. Проверьте это: http://jonas.follesoe.no/2009/12/23/automatic-inotifypropertychanged-using-dynamic-proxy/

PostSharp также преуспевает в этом случае использования, но это делается путем объединения времени компиляции по сравнению с JIT во время выполнения. http://www.postsharp.net/aspects/examples/inotifypropertychanged

Надеюсь это поможет

person kellyb    schedule 02.07.2013

Может быть, что-то вроде этого сработает:

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; 
    }
person Siraj Mansour    schedule 02.07.2013
comment
Спасибо за ответ. Я считаю, что IL испускает или компилирует так, как это должно быть сделано, и ваш код может отлично работать, однако этот интерфейс содержит только образцы, поэтому я подумал, что существует какая-то библиотека, делающая это в общем виде. - person user2542183; 02.07.2013
comment
@user2542183 user2542183 Ну, вы можете создать свою собственную библиотеку и сделать ее более гибкой, передав текст кода в функцию создания в качестве параметра. Потому что реализация определенного интерфейса должна быть где-то определена. Проголосовать или отметить как ответ :) ? - person Siraj Mansour; 02.07.2013
comment
о да, когда-нибудь я это сделаю, но я надеялся, что что-то подобное уже существует - person user2542183; 02.07.2013

В качестве альтернативы вы могли бы Фоди. Он будет делать все это и многое другое без необходимости создавать собственный IL. См. https://github.com/Fody/PropertyChanged. Просто выберите его и добавьте любой атрибут в свой класс. или производным от INotifyPropertyChanged.

person Marwijn    schedule 02.07.2013