简体   繁体   English

C#在继承的类中为父级属性添加自定义属性

[英]C# add custom attributes for a parent's property in an inherited class

I'm displaying Business Object in generic DataGrids, and I want to set the column header through a custom attribute, like: 我在通用DataGrid中显示Business Object,并且想通过自定义属性设置列标题,例如:

class TestBo
 {
    [Header("NoDisp")]
    public int ID {get; set;}

    [Header("Object's name")]
    public String Name { get; set; }
}

So far, so good, but I'd also want to separate my display from my data, by inheritance: 到目前为止,一切都很好,但是我还想通过继承将显示内容与数据分开:

class TestBO
{
   public int ID {get; set;}
   public String Name { get; set; }
}

class TestPresentationBO : TestBO
{
  //Question: how to simply set the Header attribute on the different properties?
}

I see a solution via reflection with a SetCustomAttribute in the Child constructor, but it will be cumbersome, so is there a simple and elegant trick for this problem? 我在Child构造函数中使用SetCustomAttribute通过反射看到了一个解决方案,但这将很麻烦,所以有没有简单而优雅的方法来解决此问题?

Please prevent me from breaking the data/presentation separation ;o) 请防止我破坏数据/表示的分隔; o)

Question: how to simply set the Header attribute on the different properties? 问题:如何简单地在不同属性上设置Header属性?

There is no way to set an attribute on an inherited member the way you have suggested, since attributes are specific to a type. 由于属性是特定于类型的,因此无法按照建议的方式在继承的成员上设置属性。 SetCustomAttribute won't help you - it's only any good when you construct new types at runtime . SetCustomAttribute不会帮助您-只有在运行时构造新类型时,它才有好处。 Once an attribute has been compiled in you cannot change it at runtime, since it's part of the metadata. 编译属性后,您将无法在运行时对其进行更改,因为它是元数据的一部分。

If you want to maintain the separation you will have to find another way. 如果要保持分离,则必须寻找另一种方法。

(You could make the properties virtual, override them in the Presentation class and add attributes on the overrides, but this looks dodgy and doesn't really separate anything - you end up with a complete TestBO class in your TestPresentationBO anyway...) (您可以将属性设置为虚拟属性,在Presentation类中覆盖它们,并在覆盖上添加属性,但这看起来很狡猾,并且没有真正分开任何内容-无论如何,您最终在TestPresentationBO中得到了一个完整的TestBO类...)

Make the properties in TestBo virtual and override them in TestPresentationBO . 将属性在TestBo虚拟化,并在TestPresentationBO覆盖它们。 That way you can add the attributes. 这样,您可以添加属性。

You can do it like WCF RIA Services. 您可以像WCF RIA服务一样进行操作。 Add an attribute to TestBO, like [Presentation] taking a type as parameter. 将属性添加到TestBO,例如[Presentation]以类型作为参数。 This new type will redefine the properties, but with the presentation attributes. 此新类型将重新定义属性,但具有表示属性。 At run-time, you have to get the identity of the new type and get the custom attributes of its properties. 在运行时,您必须获取新类型的标识并获取其属性的自定义属性。

Or forget about the attribute and have a dictionary mapping the BO with the presentation BO class. 或者忘记属性,并拥有一个将BO与表示BO类映射的字典。 This presentation BO class does the same thing as above, ie redefine properties with custom attributes. 此演示BO类的功能与上述相同,即使用自定义属性重新定义属性。

the presentation BO class is never instantiated, it is simply reflected upon to get presentation info. 演示文稿BO类从不实例化,只需将其反射即可获得演示文稿信息。

Just thinking, can't you solve this with partial classes and the MetadatatypeAttribute ? 只是在想,您不能使用部分类和MetadatatypeAttribute解决此问题吗? MVC2 uses this pattern for Model validation. MVC2使用此模式进行模型验证。

Are you using the MVVM (model view view-model) pattern? 您是否正在使用MVVM(模型视图视图模型)模式? It seems to me, and partly from the other answers, that you can't really do this with the custom attributes like you want. 在我看来,部分地从其他答案来看,您无法真正使用所需的自定义属性来执行此操作。 But, it also seems to me that your TestPresentationBO is really just like a "View Model" for TestBO . 但是,它也似乎我说你TestPresentationBO真的就像一个“视图模式” TestBO A view model is basically a sort of wrapper or surrogate for a business or logic class--which is basically what you want. 视图模型基本上是业务或逻辑类的包装或代理,这基本上就是您想要的。 (This summary of a view model may not be 100% accurate; I'm just starting out with MVVM myself.) (视图模型的摘要可能不是100%准确;我只是从MVVM开始。)

You can create a TestBOViewModel to wrap TestBO , then pass the collection of TestBOViewModel to the datagrid. 您可以创建一个TestBOViewModel来包装TestBO ,然后将TestBO的集合TestBOViewModel给datagrid。 Of course, you can decorate the properties exposing the wrapped class with [Header("Object's name")] etc. This doesn't use inheritance, but I don't see why you'd need to use inheritance in this situation. 当然,您可以用[Header("Object's name")]等装饰暴露包装的类的属性。这不使用继承,但是我不明白为什么在这种情况下需要使用继承。 Using a view model, does, however, cleanly separate your presentation (view) from your data (model) by using the wrapper (view model). 但是,使用视图模型确实通过使用包装器(视图模型)将演示文稿(视图)与数据(模型)清晰地分开。

For more info on the MVVM pattern, I found this to be an interesting read: WPF Apps With The Model-View-ViewModel Design Pattern . 有关MVVM模式的更多信息,我发现这很有趣: 具有Model-View-ViewModel设计模式的WPF应用程序

Something like this. 这样的事情。 Of course, you can add validation and other goodies in here too. 当然,您也可以在此处添加验证和其他功能。

public class TestBOViewModel // extend from DependencyObject 
{                            // if you want to use dependency properties

    private TestBO _myBO;

    public TestBOViewModel(TestBO bo)
    {
        _myBO = bo;
    }

    [Header("NoDisp")]
    public int ID 
    {
        get { return _myBO.ID; }
        set { _myBO.ID = value; }
    }
}

For C# 6.0 you can easily hide inherited members and introduce your own attributes. 对于C#6.0,您可以轻松隐藏继承的成员并引入自己的属性。 This might, however, hide any attributes on the original property. 但是,这可能会隐藏原始属性上的所有属性。 Also this simplified syntax makes the property read-only, so you might need to pipe the get/set yourself. 同样,这种简化的语法使属性变为只读,因此您可能需要自己通过管道传递获取/设置。

public class User
{
    public string Login { get; set; }
}


public class UserDetail : User
{
    [Display(Name = "Login:")]
    public new string Login => base.Login;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM