【问题标题】:ShouldSerializeXXX() Dynamic ImplementationShouldSerializeXXX() 动态实现
【发布时间】:2021-01-19 12:36:04
【问题描述】:

我正在制作一个带有“propertygrid 控件”的表单应用程序。
我希望所有属性始终以非粗体文本显示 --- 始终将所有属性视为“默认”值。而且这个“测试”类有很多属性。
我认为最好的方法是动态实现“ShouldSerializeXXX”方法。手动实现缺乏灵活性,不智能。

我知道使用“DynamicMethod 类”动态实现函数的方法[https://docs.microsoft.com/en-US/dotnet/api/system.reflection.emit.dynamicmethod?view=net-5.0]。但是'ShouldSerializeXXX'函数仅仅通过定义就有效果,我不知道如何实现这个函数。
谁能告诉我这样做的方法?对不起我的英语不好。
public class Test
{
      public int AAA {get;set;}
      public string BBB {get;set;}
      public bool CCC {get;set;}
      ...
      ...

      //This class has a lot of property, so I want to dynamically implement the function like this:
      private bool ShouldSerializeAAA(){ return false; }
      private bool ShouldSerializeBBB(){ return false; }
      ...
}

【问题讨论】:

标签: c# .net winforms propertygrid


【解决方案1】:

动态实现一个需要通过反射发现的方法并非易事,需要动态创建Test 的子类型,并确保所有实例实际上都属于子类型 - 不是一个吸引人的提议。

不过,还有一些更吸引人的选择;

  1. 生成额外的方法 - 这可能是几行丢弃的反射代码(以及检查它们是否都存在的单元测试),只是吐出许多版本的@987654322 @
  2. 查看类型描述符/属性描述符 API;自定义 type-description-provider 可以提供自定义属性描述符,它们可以决定是否需要序列化某些内容;只是 default 实现寻找ShouldSerialize{Name}()

老实说,选项 1 似乎是迄今为止最简单的选项 - 它在运行时涉及更少的混乱;您可以在几分钟内实现选项 1,包括测试以确保您不会错过任何新的

【讨论】:

  • 感谢您的回答。我有一个问题:什么是“额外属性”?你的意思是生成'public bool ShouldSerialize{Name}() => false;'的属性吗?方法?
  • @J.Green 我指的是额外的方法;只需自动生成它们,然后编写一个测试,使用反射检查它们是否都存在
【解决方案2】:

基本思想是使用自定义类型描述符,因为它已在 Marc 的回答中解决。你可以在我的帖子here 中看到一个实现。通过更改 ShouldSerializeValue 的覆盖并返回 false,您可以轻松地使链接的帖子为您工作。就是这样。

但在这里我想分享另一个选项,一个更短的答案,它需要更少的努力,但基本上为你做同样的事情。将对象传递给 PropertyGrid 时使用代理:

假设你有一个像这样的通用类:

public class MyClass
{
    public string MyProperty1 { get; set; }
    public string MyProperty2 { get; set; }
    public string MyProperty3 { get; set; }
}

这是您使用代理的方式:

var myOriginalObject = new MyClass();
this.propertyGrid1.SelectedObject = new ObjectProxy(myOriginalObject);

这是更改属性后的结果:

这是ObjectProxy,它是从CustomTypeDescriptor 派生的一个类,它会为你创造奇迹。这是课程:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
public class ObjectProxy : CustomTypeDescriptor
{
    public object Original { get; private set; }
    public List<string> BrowsableProperties { get; private set; }
    public ObjectProxy(object o)
        : base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o)) => Original = o;
    public override PropertyDescriptorCollection GetProperties(Attribute[] a)
    {
        var props = base.GetProperties(a).Cast<PropertyDescriptor>()
            .Select(p => new MyPropertyDescriptor(p));
        return new PropertyDescriptorCollection(props.ToArray());
    }
    public override object GetPropertyOwner(PropertyDescriptor pd) => Original;
}
public class MyPropertyDescriptor : PropertyDescriptor
{
    PropertyDescriptor o;
    public MyPropertyDescriptor(PropertyDescriptor originalProperty)
        : base(originalProperty) => o = originalProperty;
    public override bool CanResetValue(object c) => o.CanResetValue(c);
    public override object GetValue(object c) => o.GetValue(c);
    public override void ResetValue(object c) => o.ResetValue(c);
    public override void SetValue(object c, object v) => o.SetValue(c, v);
    public override bool ShouldSerializeValue(object c) => false;
    public override AttributeCollection Attributes => o.Attributes;
    public override Type ComponentType => o.ComponentType;
    public override bool IsReadOnly => o.IsReadOnly;
    public override Type PropertyType => o.PropertyType;
}

【讨论】:

    猜你喜欢
    • 2015-04-22
    • 1970-01-01
    • 1970-01-01
    • 2019-03-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多