【问题标题】:C# Custom Attribute code -> Look at the field that it was associated withC# 自定义属性代码 -> 查看与之关联的字段
【发布时间】:2013-07-19 15:03:05
【问题描述】:

我有一个在我的自定义 DB ORM 工具中使用的 C# 类,称为 DbFieldAttribute。

我把它放在我的领域,像这样:

[DbField("User_Id")]
public int UserId{ get; set; }

挑战:从我的属性构造器代码中,获取与属性关联的字段的FieldInfo。在上述情况下,它将为我提供 UserId 的 FieldInfo。

任何帮助都会很棒。谢谢。

【问题讨论】:

  • 它是一个属性,而不是一个字段,所以通过反射获取所有属性并检查每个PropertyInfo 是否具有所需的自定义属性。
  • 属性不会神奇地触发.. 必须有东西触发它们。当您检查属性是否存在时,您可以通过您的属性传递对PropertyInfo 的引用。
  • 谢谢。该属性适用于属性和字段,我不小心显示了其中一种属性类型。
  • @Jeppe:用你说的反射获取所有属性,但是我什至如何确定它附加到的对象,然后,我怎么知道我是否正在查看 write 属性?这是最初问题的核心
  • 我不确定我是否正确理解了你,但我想你可以做类似typeof(TheClassYouHave).GetProperties.Where(pi => pi.GetCustomAttributes(typeof(DbFieldAttribute), false).Length != 0) 或类似的事情。这只是为您提供了该类的 所有 具有该属性的公共属性。

标签: c# reflection custom-attributes


【解决方案1】:

不幸的是,据我所知,没有办法完成您的要求。

但是,如果您没有必要在构造函数中获取 PropertyInfoFieldInfo 对象,而是将其传递给方法,您会感到满意,那么有一个可能的解决方案。

首先,您的 DbField 类需要按以下方式定义。

class DbField : Attribute
{
    public DbField(string source) { }

    public void GetInstance(PropertyInfo source)
    {
        Console.WriteLine(source.Name);
    }
}

然后您需要定义以下类,该类将获取所有(在这种情况下)标有 DbField 属性的属性,并将它们传递给 GetInstance(PropertyInfo) em> 方法。

class ActivateAttributes
{
    public ActivateAttributes(object source)
    {
        source.GetType()
              .GetProperties()
              .Where(x => x.GetCustomAttributes().OfType<DbField>().Any())
              .ToList()
              .ForEach(x => (x.GetCustomAttributes().OfType<DbField>().First() as DbField).GetInstance(x));
    }
}

触发这个过程的方式是在一个抽象类中,它是这样定义的。

abstract class AbstractDecoratedClass
{
    public AbstractDecoratedClass()
    {
        new ActivateAttributes(this);
    }
}

现在您的目标类(其属性由 DbField 属性修饰)只需要从该类派生,这样您就不会被构造函数内部的调用所困扰。

class DecoratedClass : AbstractDecoratedClass
{
    [DbField("User_Id")]
    public int UserId { get; set; }

    [DbField("User_Id2")]
    public int UserId2 { get; set; } 
}

您现在只剩下测试此处显示的解决方案了。

class Program
{
    static void Main()
    {
        new DecoratedClass();

        Console.Read();
    }
}

【讨论】:

  • 这似乎比它需要的要复杂一些。使此解决方案起作用的关键(帮助我解决此问题的相同关键)是外部需要将类或 prop/fieldinfo 传递给属性。我所做的只是将 FieldName 的属性更改为一对重载方法,期望将 propertyinfo 或 fieldinfo 传递给它。然后,如果从未设置过 FieldName,它只会从信息中返回名称。
  • 两种方式都可以解决问题,只是没有我希望 .NET 处理的那么优雅。在大多数其他情况下,您可以使用堆栈跟踪信息来查找父级,但在这种情况下,堆栈跟踪解析回 ORM 而不是类字段/属性。 -- 谢谢。
  • 我希望我可以将成功答案应用于您发布的解决方案和我的解决方案,因为您确实提供了有效的解决方案。我选择了我的,因为我觉得实现/理解它是一个更简单的选择。谢谢。
【解决方案2】:

正如@Mario 指出的那样,无法直接解决该解决方案,但这是我最终采用的解决方案。

关键是要知道仅属性无法知道此信息,但在调用它时,可以合理地预期 FieldInfo 或 PropertyInfo 也可用。

我最初的问题是我的 ORM 代码查看属性以确定字段/属性是否与数据库字段相关。然后,我有一些实例,其中类中的 Prop/Field 名称与数据库不匹配,原因是使其更符合 Code/Db 的逻辑。在这些情况下,我需要传入一个要使用的字段名称而不是实际字段。我希望该属性可以做更多的工作,或者至少有助于使其对将来使用它的任何代码更加明显。

(我删除了与此解决方案无关的 xml cmets 和额外代码)

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class DbFieldAttribute : Attribute
{
    private string fieldName = "";

    public DbFieldAttribute() { }

    public DbFieldAttribute(string fieldName)
    {
        this.fieldName = fieldName;
    }

    public string FieldName(PropertyInfo pi)
    {
        if (this.fieldName != "") return this.fieldName;
        else return pi.Name;
    }

    public string FieldName(FieldInfo fi)
    {
        if (this.fieldName != "") return this.fieldName;
        else return fi.Name;
    }

现在,当我的 ORM 代码需要字段名称时,它必须传入与该字段相关的字段或属性信息。这意味着所需要的现在是属性使用中固有的,而不是需要在外部代码中派生。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-02
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 2011-12-10
    • 2011-09-20
    • 1970-01-01
    相关资源
    最近更新 更多