如何获取实例变量的最顶层类型?

5
假设我有一个声明为给定基类的实例变量。我想找到该对象实际上是什么原始的、最高层次的类型,而不是基类。我该怎么做?
我有一个验证属性,类似于PostSharp,因此反射命中在编译时,并且由于CompileTimeValidation方法,因此是无意义的。我只是不知道该如何去做。扫描IsSubclassOf并没有帮助,因为我会得到多个错误的结果。
为了提供上下文,我有一个基本的Entity类型。我从这个类型派生出定义各种Entity类型的所有内容。我使用策略属性对这些类型(包括基本的Entity)进行装饰。PostSharp方面在编译时验证某些策略约束。我想能够只对基本的Entity类型进行方面验证,以便验证Entity和它的所有派生类型。我可以看到验证已经发生。但是,它被处理为一个Entity,而不是DerivedEntity。为了评估DerviedEntity上的策略,我需要专门装饰那个类。如果可能的话,我不想这样做,只想装饰Entity
本质上,我想将我的验证集中在基类上,因为所有派生类的验证模式都是相同的。但是,派生类中的值可能会改变,我需要进行一些边界检查。
编辑:让我们添加一些代码。
[EnforceMaxLifetimePolicy]
[LifetimePolicy]
public class Entity<T>
{
    public string Key { get; set; }
    public T Object { get; set; }

    public TimeSpan EntityLifetime
    {
        get
        {
            var lifetimePolicy =
                Attribute.GetCustomAttribute(GetType(), typeof(LifetimePolicyAttribute)) as LifetimePolicyAttribute;

            return new TimeSpan(lifetimePolicy.Hours, lifetimePolicy.Minutes, 0);
        }
    }
}

[Serializable]
[AttributeUsage(AttributeTargets.Class)]
internal class LifetimePolicyAttribute : Attribute
{
    public readonly short Hours;
    public readonly short Minutes;

    public LifetimePolicyAttribute(short hours, short minutes)
    {
        Hours = hours;
        Minutes = minutes;
    }

    public LifetimePolicyAttribute()
    {
        Minutes = 1;
    }
}

[Serializable]
[AttributeUsage(AttributeTargets.Class)]
internal class EnforceMaxLifetimePolicyAttribute : OnMethodBoundaryAspect
{
    public override bool CompileTimeValidate(MethodBase method)
    {
        var type = method.GetType();

        var lifetimePolicy = GetCustomAttribute(type, typeof(LifetimePolicyAttribute)) as LifetimePolicyAttribute;

        if (lifetimePolicy != null && lifetimePolicy.Hours + lifetimePolicy.Minutes / 60 > 24)
        {
            throw new InvalidAnnotationException($"Lifetimes can not exceed 24 hours. The lifetime on {type.FullName} is invalid.");
        }

        return true;
    }
}

[LifetimePolicy(hours: 24, minutes: 0)]
internal class ShoppingCartEntity : Entity<ShoppingCart>
{
}

正如你所看到的,ShoppingCartEntity没有[EnforceMaxLifetimePolicy]。它在基类Entity上。然而,我仍希望Enforce属性实体也适用于派生类型,这就是为什么我将Inherited标志保留为默认值(true)。


1
obj.GetType() 对你有用吗? - Andrei
1
我猜你的最高类型总是 object :) - Ilya Chernomordik
很遗憾,我不能这样做。如果我这样做,我只会在基本“实体”上评估策略属性,并且无法获取适当子类型的属性。 - Bigsby
2
你能展示一些代码吗?我很难理解实际的问题。 - Patrick Hofman
@PatrickHofman 添加了代码 - Bigsby
显示剩余2条评论
3个回答

1

我不太理解你的问题,但你可以通过以下方法找到答案:

1. 查看对象的实际类型(使用 obj.GetType()):

if (obj.GetType() == typeof(Entity)) { ... }

2. 如果对象是某种类型的派生类(使用“is”运算符):

if (obj is Entity) { ... }

1
显然,PostSharp消除了这个需要。它通过Multicasting支持自动应用于派生类型。因此,lifetime属性看起来像这样:
[Serializable]
[AttributeUsage(AttributeTargets.Class)]
[MulticastAttributeUsage(Inheritance = MulticastInheritance.Multicast)]
internal class EnforceMaxLifetimePolicyAttribute : OnMethodBoundaryAspect
{
    public override bool CompileTimeValidate(MethodBase method)
    {
        var type = method.DeclaringType;

        var lifetimePolicy = GetCustomAttribute(type, typeof(LifetimePolicyAttribute)) as LifetimePolicyAttribute;

        if (lifetimePolicy.Hours + lifetimePolicy.Minutes / 60 > 24)
        {
            throw new InvalidAnnotationException($"Lifetimes can not exceed 24 hours. The lifetime on {type.FullName} is invalid.");
        }

        return true;
    }
}

"[MulticastAttributeUsage(Inheritance = MulticastInheritance.Multicast)]这一行会让PostSharp自动将其应用于ShoppingCartEntity和其他相关内容。"

0
你可以循环遍历每个基类,直到触底。在找到第一个所需属性的情况下停止:
var type = method.GetType();

do
{
    var lifetimePolicy = GetCustomAttribute(type, typeof(LifetimePolicyAttribute)) as LifetimePolicyAttribute;
    if (lifetimePolicy != null)
    {
        // process
        break; // out of the do...while
    }
} while ((type = type.BaseType) != null);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接