动态添加新方法、属性到现有类中所需的帮助

发布于 2024-09-03 03:51:20 字数 3957 浏览 5 评论 0原文

我不确定在Dot Net中是否可以实现这种实现。以下是信息

目前我们正在开发一个使用 COM+、ASP、XSL、XML 技术完成的应用程序。它是一个多层体系结构应用程序,其中 COM+ 充当 BAL。任何 CRUD 操作的执行步骤都将使用单独的 UI 进行定义,该 UI 使用 XML 来存储信息。 BAL读取XML并理解定义的执行步骤并执行DLL中相应的方法。与 EDM 非常相似,我们有自定义模型(使用 XML),它确定对象的哪些属性是可搜索、可检索等。BAL 基于此信息构造查询并调用过程来获取数据。

在当前的应用程序中,BAL 和 DAL 都可以高度自定义,无需更改任何代码。结果将以 XML 格式传输到表示层,表示层根据收到的数据构建 UI。

现在我正在创建一个处理员工信息的迁移项目。它还将遵循 N 层架构,其中表示层与 BAL 通信,BAL 连接到 DAL 以返回数据。

问题是,在我们现有的版本中,我们将每个信息以其本机形式处理为 XML(没有对象转换等),但是在迁移项目中,团队确实对利用 OOP 开发模型感兴趣,其中每个信息都是从 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 中完成这个任务吗?

我想过使用匿名类,但是匿名类的问题是

我们不能在其中包含方法。 我不确定如何适合集合对象(这将成为一个匿名类) 不确定数据网格/用户控件绑定等。

我还考虑过使用 CODEDom 来创建运行时类,但不确定内存、性能问题。此外,这些类只能创建一次,并且必须使用相同的类,直到发生另一次更改为止。

请帮助我解决这个问题。任何类型的帮助材料/神秘代码/链接都会有所帮助。

更新:

感谢您提供的答案,这些答案使我能够研究我没有想到的不同领域。

我在问题中错过了一项信息。 UI 代码也将作为 DLL 而不是源代码。客户可以自由创建新代码并附加到 UI,但不能通过代码更改现有 UI。我们有一个设计器,它将显示可选择的、可显示的属性,客户可以从中选择向用户显示数据。这样他们就可以改变用户界面的外观和感觉。他们还可以使用此模型更改绑定属性。

如果我在问题中给出了这篇文章,我可能会得到更多答案,并且可能会让您清楚地了解到底发生了什么。

有了上面的内容,下面是我的新想法,

我还在考虑使用 CodeDom 模型单独创建类并将其迁移到 UI。下面是我的想法:

创建一个控制台应用程序来读取我们结构的 XML 文件。它将包含系统中可用的属性和类。还创建一个 UI 来操作 XML 文件来创建类。在控制台中使用 COdeDom 生成类和方法。使用库或 shell 命令编译它们。将创建的类移动到UI中,现在UI将识别新的类并可以显示属性。

这可能不会造成任何内存占用和高内存利用率/泄漏。我们还替换了 DLL,这很简单。唯一的问题是班级的产生。它必须以团队能够在此 UI 中执行任何操作的方式复杂化。你们觉得怎么样

I am not sure whether it is possible to achieve this kind of implementation in Dot Net. Below are the information

Currently we are on an application which is done in COM+, ASP, XSL, XML technologies. It is a multi tier architecture application in which COM+ acts as the BAL. The execution steps for any CRUD operation will be defined using a seperate UI which uses XML to store the information. BAL reads the XML and understands the execution steps which are defined and executes corresponding methods in DLL. Much like EDM we have our custom model (using XML) which determines which property of object is searchable, retrievable etc. Based on this information BAL constructs queries and calls procedures to get the data.

In the current application both BAL and DAL are heavily customizable without doing any code change. the results will be transmitted to presentation layer in XML format which constructs the UI based on the data recieved.

Now I am creating a migration project which deals with employee information. It is also going to follow the N Tier architecture in which the presentation layer communicates with BAL which connects to DAL to return the Data.

Here is the problem, In our existing version we are handling every information as XML in its native form (no converstion of object etc), but in the migration project, Team is really interested in utilizing the OOP model of development where every information which is sent from BAL need to be converted to objects of its respective types (example employeeCollection, Address Collection etc).

If we have the static number of data returned from BAL we can have a class which contains those nodes as properties and we can access the same. But in our case the data returned from our BAL need to be customized. How can we handle the customization in presentation layer which is converting the result to an Object.

Below is an example of the XML returned

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

If these are the only columns then i can write a class which is like

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

This class will be provided to customers and consultants as DLLs. We will not provide the source code for the same.

Now when the consultants or customers does customization(example adding country to address and adding passport information object with employee object) they must be able to access those properties in these classes, but without source code they will not be able to do those modifications.which makes the application useless. Is there is any way to acomplish this in DotNet.

I thought of using Anonymous classes but, the problem with Anonymous classes are

we can not have methods in it.
I am not sure how can i fit the collection objects (which will be inturn an anonymous class)
Not sure about datagrid / user control binding etc.

I also thought of using CODEDom to create classes runtime but not sure about the meory, performance issues. also the classes must be created only once and must use the same till there is another change.

Kindly help me out in this problem. Any kind of help meterial/ cryptic code/ links will be helpful.

Update:

Thanks for the answers that are provided which gave me to look into different areas which i had not thought of.

There is one peice of info i missed in the question. The UI code also will be as DLLs not as source code. The customers are free to create new Code and attach to the UI but they cannot change the existing UI through code. We are having a designer which will display the selectable, displayable properties from which the customer can select to display data to user. This way they can change the look and feel of the UI. Also they can change the binding property using this model.

If i had given this piece in the question i might have got some more answer and might given you a clear idea on what exactly is happening.

With the above piece, below is my new thought

I am also thinking something of using CodeDom model to create the classes seperately and migrating the same to UI. Below is my thought

Create a console application which reads a XML file of our structure. it will contains the properties and classes that are available in the system. ALso create an UI to manipulate the XML file to create classes. in the console Use COdeDom to generate the classes and methods. Compile them using libraries or shell commands. Move the created classes to UI, Now UI will recogonize the new classes and can display the properties.

This might not create any memory hogging and high memory utilization/leaks. also we are replacing the DLLs which is simple. Only problem is the class generation. it must be sophasticated in a way the team must be able to perform any operation in this UI. what do you guys think

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

ゃ懵逼小萝莉 2024-09-10 03:51:20

如果您允许他们从您的基类继承新的 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>();

If you allow them to inherit new Address and Employee classes from your base classes that should do the trick.

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

Then a derived employee would look something like this

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

If you want the stronly typed collection to be of EmployeePlus you can simple define your collections like this, if you need to...

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

Now a strongly typed collection of Employee and derived objects can be used as follows

EmployeeCollection<EmployeePlus> employees = 
  new EmployeeCollection<EmployeePlus>();
深空失忆 2024-09-10 03:51:20

尝试使用 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;

    }
}

Try to work with 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;

    }
}
揽清风入怀 2024-09-10 03:51:20

这似乎是一个相当奇怪的设置,但是有很多方法可以实现您想要的功能:

  • 类继承(可能使
    你的基类抽象但是
    部分类是另一种选择)
  • 使用接口而不是类并让您的客户
    担心实现
  • 扩展方法 (ref1ref2),通常用于
    扩展第三方代码,但不是
    通常预计会被使用。
  • 装饰器

通常来说,我希望以您的方式使用接口场景,但如果您也尝试混合行为,我会冒险猜测此时重构可能会太痛苦,而类继承就是您最终的结果。

This seems quite an odd setup, but there's a number of ways you could do what you want:

  • Class inheritance (probably making
    your base classes abstract but
    partial classes are another option)
  • working to interfaces instead of classes and letting your customers
    worry about the implementation
  • extension methods (ref1, ref2) which are commonly used to
    extend third party code, but are not
    normally expected to be used.
  • decorators

Normally speaking I'd expect to be working with Interfaces in your kind of scenario, but if you're also trying to mix in behaviour I'd hazard a guess that refactoring that may be too painful at this point and class inheritance is where you'll end up.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文