c#—是否可以声明一个类,其中所有字段都是另一个类的字段的包装器?

本文关键字:字段 包装 另一个 是否 声明 一个 | 更新日期: 2023-09-27 18:09:56

请随意修改标题,我想不出更好的了='

给定下面的示例类

public class Person
{
    public string Name;
    public int ID;
    public string City;
}

我需要创建另一个镜像类,其中每个字段实际上是原始类的包装器:

public class PersonMirror
{
    public FieldWrapper<string> Name;
    public FieldWrapper<int> ID;
    public FieldWrapper<string> City;
}
public class FieldWrapper<T>
{
    public T Value;
    public bool someBool;
    public int someCounter;
    // ..whatever
}

问题是,我有很多类要镜像,其中一些类有很多字段!此外,原始类可能会不时更改(添加/删除/重命名字段),并且每个更改都必须应用于镜像类—这对于可维护性来说不是一个好的实践。

我的问题是-是否有一种类型安全的方式自动执行声明(而不是创建,例如生成的代码)这样的镜像类?

编辑:让我们从头开始。在我们的SOA系统中,有一个资源访问服务(serviceX)负责更新DB中的条目。其他服务向它发送它们想要执行的修改—在json中,类似于:{ID: 123, name : "myNewName"}。然后serviceX将构建一个更新查询发送到DB。然而,有一个要求,serviceX将公开一个POCO接口,这样接口将是独立于语言的,所以像(p=> p.name, "MyNewName")这样的表达式是不允许的。另一个要求是类型安全,所以json也不允许。目前,上述解决方案是我们提出的最好的解决方案。任何更好的解决方案都是受欢迎的!

c#—是否可以声明一个类,其中所有字段都是另一个类的字段的包装器?

在我看来,没有办法做你想做的,除了代码生成。
代码生成的方法可能不同(这可能是源代码生成+编译,发出IL代码,无论是您自己的还是现有的),但这是唯一的方法。

使用T4自动生成"WrapperClass"

下面是如何实现FieldWrapper的命题。

public class FieldWrapper<T, O>
{
    private T _item;
    private O _owner;
    private PropertyInfo _setter;
    public T Value
    {
         get { return _item; }
         set {
           if (!EqualityComparer<T>.Default.Equal(_item, value))
           {
                _item = value;
                // do some personal check
                _setter.SetValue(_owner, value);
           }
         }
    }
    public bool someBool;
    public int someCounter;
    // ..whatever
    // CTOR
    public FieldWrapper(O owner, Expression<Func<T, O>> propertyExpressionInTheOwner)
    {
       _owner = owner;
       propertyName = (propertyExpressionInTheOwner.body as MemberExpression).Member.Name;
       // get PropertyInfo using the owner and propertyName
    }
}

使用表达式行为允许您以这种方式创建fieldWrapper。

var p = new Person();
new FieldWrapper(p, (pers) => pers.Name);

这种技术的优点是,如果您更改了类,您将直接收到编译错误。

对于T4,必须加载所有类所在的程序集,用特定属性标记类模型。查看程序集,找到具有此属性的每个类,并生成包装器类关联。

您必须在每次代码更改后运行它,但是您可以创建一个代码解析应用程序。

列出需要替换的关键字,如" string ", " int "。逐行读取文件。查找类的定义(行中包含"class"),然后将其中任何给定关键字的每个实例替换为:

"FieldWrapper<" + keyword + ">"

您可能希望通过检查"("answers")"以及左花括号来删除方法内部(可能在方法签名/返回类型本身中)的关键字替换。当到达右花括号时,继续操作。您可以通过将嵌套级别存储在一个整数中来实现,当点击'{'时增加它,当到达'}'时减少它。