Требуется помощь в добавлении новых методов, свойств в существующие классы динамически - PullRequest
0 голосов
/ 30 мая 2010

Я не уверен, возможно ли добиться такого рода реализации в Dot Net. Ниже приведена информация

В настоящее время мы находимся в приложении, которое сделано в технологиях COM +, ASP, XSL, XML. Это приложение многоуровневой архитектуры, в котором COM + действует как BAL. Шаги выполнения для любой операции CRUD будут определены с использованием отдельного пользовательского интерфейса, который использует XML для хранения информации. BAL читает XML и понимает шаги выполнения, которые определены, и выполняет соответствующие методы в DLL. Как и в случае с EDM, у нас есть собственная модель (с использованием XML), которая определяет, какое свойство объекта можно искать, получать и т. Д. На основе этой информации BAL создает запросы и вызывает процедуры для получения данных.

В текущем приложении BAL и DAL в значительной степени настраиваются без каких-либо изменений кода. результаты будут переданы на уровень представления в формате XML, который создает пользовательский интерфейс на основе полученных данных.

Сейчас я создаю проект миграции, который касается информации о сотрудниках. Он также будет следовать архитектуре N-уровня, в которой уровень представления взаимодействует с BAL, который подключается к DAL для возврата данных.

В этом и заключается проблема: в нашей существующей версии мы обрабатываем каждую информацию в виде XML в ее собственном виде (без разговора об объекте и т. Д.), Но в проекте миграции Team действительно интересно использовать модель разработки ООП, где каждый информация, отправляемая из BAL, должна быть преобразована в объекты соответствующих типов (например, employeeCollection, Address Collection и т. д.).

Если у нас есть статический номер данных, возвращаемых из BAL, у нас может быть класс, который содержит эти узлы в качестве свойств, и мы можем получить к ним доступ. Но в нашем случае данные, возвращаемые из нашего BAL, необходимо настроить. Как мы можем обрабатывать настройку на уровне представления, который преобразует результат в объект.

Ниже приведен пример возвращаемого XML

<employees>
    <employee>
        <firstName>Employee 1 First Name</firstName>
        <lastName>Employee 1 Last Name</lastName>
        <addresses>
            <address>
                <addressType>1</addressType>
                <StreetName>Street name1</StreetName>
                <RegionName>Region name</RegionName>
            <address>
            <address>
                <addressType>2</addressType>
                <StreetName>Street name2</StreetName>
                <RegionName>Region name</RegionName>
            <address>
            <address>
                <addressType>3</addressType>
                <StreetName>Street name3</StreetName>
                <RegionName>Region name</RegionName>
            <address>
        <addresses>
    </employee>
    <employee>
        <firstName>Employee 2 First Name</firstName>
        <lastName>Employee 2 Last Name</lastName>
        <addresses>
            <address>
                <addressType>1</addressType>
                <StreetName>Street name1</StreetName>
                <RegionName>Region name</RegionName>
            <address>
            <address>
                <addressType>2</addressType>
                <StreetName>Street name2</StreetName>
                <RegionName>Region name</RegionName>
            <address>
        <addresses>
    </employee>
</employees>

Если это единственные столбцы, тогда я могу написать класс, подобный

public class Address{
    public int AddressType {get;set;};
    public string StreetName {get;set;};
    public string RegionName {get;set;};
}

public class Employee{
    public string  FirstName {get; set;}
    public string  LastName {get; set;}
    public string  AddressCollection {get; set;}
}

public class EmployeeCollection : List<Employee>{
    public bool Add (Employee Data){
    ....
    }
}

public class AddressCollection : List<Address>{
    public bool Add (Address Data){
    ....
    }
}

Этот класс будет предоставлен клиентам и консультантам в виде библиотек DLL. Мы не будем предоставлять исходный код для того же.

Теперь, когда консультанты или заказчики выполняют настройку (например, добавляя страну к адресу и добавляя объект паспортной информации с объектом сотрудника), они должны иметь возможность доступа к этим свойствам в этих классах, но без исходного кода они не смогут это сделать Изменения, которые делают приложение бесполезным. Есть ли способ сделать это в DotNet.

Я думал об использовании анонимных классов, но проблема с анонимными классами

у нас не может быть методов. Я не уверен, как я могу соответствовать объектам коллекции (которые будут inturn анонимным классом) Не уверен насчет привязки данных / пользовательского элемента управления и т. Д.

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

Пожалуйста, помогите мне в этой проблеме. Любой вид справочного материала / загадочный код / ​​ссылки будут полезны.

Обновление:

Спасибо за предоставленные ответы, которые дали мне возможность взглянуть на различные области, о которых я не думал.

Есть одна часть информации, которую я пропустил в этом вопросе. Код пользовательского интерфейса также будет как DLL, а не как исходный код. Клиенты могут создавать новый код и подключаться к пользовательскому интерфейсу, но не могут изменять существующий пользовательский интерфейс с помощью кода. У нас есть дизайнер, который будет отображать выбираемые, отображаемые свойства, из которых клиент может выбрать отображение данных для пользователя. Таким образом, они могут изменить внешний вид интерфейса. Также они могут изменить свойство привязки, используя эту модель.

Если бы я дал эту часть в вопросе, я мог бы получить больше ответов и дать вам четкое представление о том, что именно происходит.

С вышеприведенным фрагментом ниже моя новая мысль

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

Создайте консольное приложение, которое читает XML-файл нашей структуры. он будет содержать свойства и классы, доступные в системе. Также создайте пользовательский интерфейс для управления файлом XML для создания классов. в консоли Используйте COdeDom для генерации классов и методов. Скомпилируйте их, используя библиотеки или команды оболочки. Переместите созданные классы в пользовательский интерфейс. Теперь пользовательский интерфейс распознает новые классы и может отображать свойства.

Это может не привести к перегрузке памяти и высокому использованию / утечке памяти. также мы заменяем библиотеки DLL, что просто. Единственная проблема - это поколение классов. он должен быть сложным таким образом, чтобы команда могла выполнять любые операции в этом пользовательском интерфейсе. что вы, ребята, думаете

Ответы [ 3 ]

1 голос
/ 30 мая 2010

Если вы позволите им наследовать новые классы Address и Employee от ваших базовых классов, это должно сработать.

public class Employee
{
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public string AddressCollection { get; set; }
}

public class EmployeeCollection<T> : List<T> where T : Employee
{
  public bool Add(T Data)
  {
    return this.Add(Data);
  }
}

Тогда производный сотрудник будет выглядеть примерно так

public class EmployeePlus : Employee
{
  public string PassportNo { get; set; }
}

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

public class EmployeeCollection<T> : List<T> where T : Employee
{
  public bool Add(T Data)
  {
    return this.Add(Data);
  }
}

Теперь строго типизированная коллекция Employee и производных объектов может использоваться следующим образом

EmployeeCollection<EmployeePlus> employees = 
  new EmployeeCollection<EmployeePlus>();
0 голосов
/ 30 мая 2010

Попробуйте поработать с MSIL

public class RunTimeObject<T> where T : class
{

    void EmitGetter(MethodBuilder methodBuilder, FieldBuilder fieldBuilder)
    {
        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldfld, fieldBuilder);
        ilGenerator.Emit(OpCodes.Ret);
    }

    void EmitSetter(MethodBuilder methodBuilder, FieldBuilder fieldBuilder)
    {
        ILGenerator ilGenerator = methodBuilder.GetILGenerator();
        ilGenerator.Emit(OpCodes.Ldarg_0);
        ilGenerator.Emit(OpCodes.Ldarg_1);
        ilGenerator.Emit(OpCodes.Stfld, fieldBuilder);
        ilGenerator.Emit(OpCodes.Ret);
    }

    public object CreateNewObject(T obj)
    {

        AssemblyName assemblyName = new AssemblyName { Name = "assembly" };
        AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule("module");
        TypeBuilder typeBuilder = moduleBuilder.DefineType("DynamicType", TypeAttributes.Public | TypeAttributes.Class);

        foreach (var prop in obj.GetType().GetProperties())
        {
            FieldBuilder field = typeBuilder.DefineField("_" + prop.Name, typeof(string), FieldAttributes.Private);

            PropertyBuilder propertyBuilder =
                typeBuilder.DefineProperty(prop.Name,
                                 PropertyAttributes.None,
                                 typeof(string),
                                 new Type[] { typeof(string) });

            MethodAttributes methodAttributes =
                MethodAttributes.Public |
                MethodAttributes.HideBySig;

            MethodBuilder methodBuilderGetter =
                typeBuilder.DefineMethod("get_value",
                                           methodAttributes,
                                           typeof(string),
                                           Type.EmptyTypes);

            EmitGetter(methodBuilderGetter, field);


            MethodBuilder methodBuilderSetter =
                typeBuilder.DefineMethod("set_value",
                                           methodAttributes,
                                           null,
                                           new Type[] { typeof(string) });

            EmitSetter(methodBuilderSetter, field);


            propertyBuilder.SetGetMethod(methodBuilderGetter);
            propertyBuilder.SetSetMethod(methodBuilderSetter);
        }

        Type dynamicType = typeBuilder.CreateType();

        var dynamicObject = Activator.CreateInstance(dynamicType);

        var properties = dynamicType.GetProperties();

        int count = 0;

        foreach (var item in obj.GetType().GetProperties())
            properties[count++].SetValue(dynamicObject, item.GetValue(obj, null), null);

        return dynamicObject;

    }
}
0 голосов
/ 30 мая 2010

Это выглядит довольно странно, но есть несколько способов, которыми вы могли бы делать то, что вы хотите:

  • Класс наследования (возможно, делает ваши базовые классы абстрактно, но частичные классы являются еще одним вариантом)
  • работа с интерфейсами вместо классов и предоставление вашим клиентам беспокоиться о реализации
  • методы расширения ( ref1 , ref2 ), которые обычно используются для расширить сторонний код, но не обычно ожидается .
  • декораторы

Обычно, я бы ожидал работать с интерфейсами в вашем сценарии, но если вы также пытаетесь смешивать поведение, я бы рискнул предположить, что рефакторинг, который может быть слишком болезненным в данный момент, и наследование классов это то место, где вы окажетесь.

...