【问题标题】:Is it possible to pass an attribute argument from a derived class to its base class?是否可以将派生类的属性参数传递给其基类?
【发布时间】:2013-03-03 14:58:02
【问题描述】:

是否可以将派生类的属性参数传递给其基类?

本质上,我正在尝试从派生类中设置属性的属性参数。

  • 如何在 C++ 中完成

    public class HasHistory<T, string name> {
        public HasHistory() {
            History=new History<T>();
        }
    
        // here's my attribute
        [BsonElement(name)]
        public History<T> History {
            get;
            protected set;
        }
    }
    

    但是,非类型模板参数在 C++ 中是合法的,但在 C# 中是非法的

  • C# 中的一个意想不到的解决方法

    我意识到我可以将属性设为虚拟,并在派生类中添加属性。但是我会在构造函数中调用一个虚函数,虽然这可能有效,但这是不好的做法。

    我确实想进行该调用,因为我希望基类构造函数初始化成员;这实际上是基类的重点。

    public class HasHistory<T> {
        public HasHistory() {
            // this will be called before Derived is constructed
            // and so the vtbl will point to the property method
            // defined in this class.
            // We could probably get away with this, but it smells.
            History=new History<T>();
        }
    
        // here's my property, without an Attribute
        public virtual History<T> History {
            protected set;
            get;
        }
    }
    
    public class Derived: HasHistory<SomeType> {
        // crap! I made this virtual and repeated the declaration
        // just so I could add an attribute!
        [BsonElement("SomeTypeHistory")]
        public virtual HasHistory<SomeType> History {
            protected set;
            get;
        }
    }
    

    所以我想我不能把属性放在基类中,而是把它放在派生类属性上,该属性使用/是根据受保护的基类属性实现的,但这太麻烦了,它消除了通过使用基类。

所以有一个好方法可以做到这一点,对吧?正确的?

如何重新定义继承自基的派生类的属性不覆盖派生类中的属性

【问题讨论】:

  • 不确定你对泛型中的&lt;T, string name&gt; 部分做了什么。
  • @ChrisSinclair 无效,但他试图说明他想要一个像 C++ 模板参数这样的 C# 机制。
  • 您是否尝试在基类中应用该属性?据我所知,不可能将变量传递给属性,因为属性是在编译时而不是运行时处理的。
  • 以上没有多大意义。类型变量实际上更类似于占位符,它们根据需要被请求的实际类型替换(当实例化泛型类的实例时)。例如,如果您要使用string,那么您的属性将显示[BsonElement(string)],这对编译无效。
  • 你希望用这个属性完成什么,也许还有另一种解决问题的方法?

标签: c# attributes base derived-class


【解决方案1】:

更新:该死,你已经考虑过了。我应该在发布之前更新:)

不幸的是,您想要做的远远超出了 C# 的属性机制的范围。泛型与模板不同,因此这种解决方法几乎可以做到。

大多数情况下,无论如何您都会在顶层定义一个属性,所以通常这不是问题。当它一个问题时 - 显然在你的情况下 - 那么你必须使用丑陋的解决方法。

原始答案如下...


如果我正确理解了该示例,您希望根据派生类型中/由派生类型声明的某个值将属性应用于类成员。由于 C# 不支持泛型的非类型参数,因此您需要另一种方法来执行此操作。

您可以做的一件事是像这样覆盖后代类中的属性:

public class HasHistory<T>
{
    public HasHistory() 
    {
        History = new History<T>();
    }

    public virtual History<T> History { get; protected set; }
}

public class MyHistory<T> : HasHistory<T>
{
    public MyHistory()
        : base()
    {}

    [BSONElement("some name")]
    public override History<T> History 
    { 
        get
        {
            return base.History;
        }
        protected set
        {
            base.History = value;
        }
    }
}

使用BsonElement 属性的代码将使用派生HasHistory&lt;T&gt; 实例的实际 类型,因此它将查看@987654325 末尾定义的属性@ 链。鉴于上面的代码,如果我创建一个 MyHistory&lt;T&gt; 实例并将其传递给 BSON 序列化程序,它将在 MyHistory&lt;T&gt; 类中找到附加到 History 属性的属性。

但是,您可以在基础级别定义一个属性,并在必要时在派生类中覆盖它。不确定这对您的情况是否有用。

这是更多的工作,特别是因为您必须在每个派生类中执行此操作,但我认为这与在这种情况下您将要获得 C++ 模板样式一样接近。但是,我很高兴被证明是错误的:)

【讨论】:

  • 这里的问题是你现在在基础构造函数中有一个虚方法调用。我还没有找到解决办法。
  • 是的,我在发布原始答案并发现您已更新问题后发现了这一点。基本上归结为目前这超出了语言的能力范围。
  • 如果有办法“覆盖”属性就好了……不管这意味着什么。
  • 属性是 types 而不是 instances 的装饰。一个属性甚至无法找出它在装饰什么,除非你明确地告诉它作为方法调用的参数。如果你想要特定于实例的差异,你需要一个 property.
  • 只是为了证明 C# 比我们通常认为的更灵活,而且在幕后更危险....如果你不关心 mono 兼容性,请不要不介意有很多代码来支持它,您可以通过使用TypeDescriptor 在运行时操作类型的元数据来更接近您所追求的。例如:geekswithblogs.net/abhijeetp/archive/2009/01/10/…
猜你喜欢
  • 1970-01-01
  • 2015-08-20
  • 2011-06-03
  • 1970-01-01
  • 2012-03-06
  • 2019-12-24
  • 2016-09-20
  • 1970-01-01
相关资源
最近更新 更多