2

我正在制作一个带有“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; }
      ...
}
4

2 回答 2

0

Dynamically implementing a method that needs to then be discovered by reflection is not trivial, and would require dynamically creating a sub-type of Test and making sure that all your instances are actually of the sub-type - not an appealing proposition.

There are some more appealing options, though;

  1. generate the extra methods - this could be a few lines of throw-away reflection code (and a unit test that checks that they all exist) that just spits out however-many versions of public bool ShouldSerialize{Name}() => false;
  2. look into the type-descriptor/property-descriptor API; a custom type-description-provider can provide custom property-descriptors, and it is they that get to say whether something needs to be serialized or not; it is just that the default implementation looks for ShouldSerialize{Name}()

Honestly, option 1 seems by far the easiest option here - and it will involve less mess at runtime; you could get option 1 implemented in a few minutes, including the test to make sure you don't miss any new ones

于 2021-01-19T13:32:28.030 回答
0

基本思想是使用自定义类型描述符,因为它已经在 Marc 的回答中得到解决。您可以在我的帖子中看到一个实现。通过更改 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;
}
于 2021-01-21T16:21:01.363 回答