Требуется помощь в динамическом добавлении новых методов и свойств в существующие классы.

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

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

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

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

Вот в чем проблема: в нашей существующей версии мы обрабатываем каждую информацию как XML в ее исходной форме (без преобразования объекта и т. д.), но в проекте миграции команда действительно заинтересована в использовании модели разработки ООП, где вся информация, которая отправленные из 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.

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

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

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

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

Обновлять:

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

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

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

С приведенной выше частью ниже моя новая мысль

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

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

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


person Albert Arul prakash    schedule 30.05.2010    source источник
comment
Разве они не могут просто декомпилировать библиотеки DLL, которые вы предоставляете, обратно в исходный код?   -  person Hans Passant    schedule 30.05.2010
comment
код будет расфускирован, что блокирует декомпиляцию.   -  person Albert Arul prakash    schedule 03.06.2010


Ответы (3)


Попробуйте работать с 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;

    }
}
person Daniel Bern    schedule 30.05.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);
  }
}

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

EmployeeCollection<EmployeePlus> employees = 
  new EmployeeCollection<EmployeePlus>();
person Chris Taylor    schedule 30.05.2010
comment
Вы были правы, конечно, частичные классы работают только тогда, когда у вас есть доступ к исходному коду :-( Я мог бы поклясться, что использовал это с вещами, предоставленными в DLL раньше, но я, должно быть, мечтал об этом....: -) - person marc_s; 30.05.2010
comment
Крис, в этом случае я считаю, что нам нужно переназначить элементы управления с новым типом. Причина, по которой я спрашиваю, заключается в том, что, например, существует сетка данных, которая привязана к коллекции классов сотрудников. Теперь, когда он модифицируется для использования класса EmployeePLus, в представлении (UI) нам нужно повторно связать все элементы управления, которые используют класс Employee в качестве своего объекта данных. - person Albert Arul prakash; 03.06.2010

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

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

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

person annakata    schedule 30.05.2010