在不知道泛型类型的情况下使用反射从属性中获取泛型特性

Getting generic attribute from a property using reflection without knowing the generic type

提问人:devklick 提问时间:6/16/2023 最后编辑:devklick 更新时间:6/16/2023 访问量:264

问:

C# 11 引入了泛型属性。是否可以在不知道其泛型类型的情况下使用方法(或类似方法)获取附加到的属性,尤其是在属性继承自另一个属性的情况下?PropertyInfoGetCustomAttribute

这是我所拥有的:

public class MyTypedAttribute<TValue> : Attribute
{ 
    public virtual TValue ProcessValue(object value) { }
}

public class MyNumberAttribute : MyTypedAttribute<int>
{ 
    public override int ProcessValue(object value) { }
}

public class MyStringAttribute : MyTypedAttribute<string>
{ 
    public override string ProcessValue(object value) { }
}

我的类具有具有一系列这些属性的属性,我想使用反射来获取它们。我通常会使用泛型函数,但是当属性本身也需要泛型参数时,这似乎不起作用(除非泛型类型在编译时是已知的,而在我的情况下,它们不是)PropertyInfo.GetCustomAttribute<>

PropertyInfo myProp = ...;
var attr = myProp.GetCustomAttribute<MyTypedAttribute<>>();

编译错误:意外使用未绑定的通用名称

似乎我可以使用非泛型等效函数,但是返回的属性是类型,似乎在不知道泛型类型的情况下我无法转换它。我们不能在强制转换时指定空尖括号,所以必须指定一个类型,但我不知道类型是什么。我唯一能想到的就是用作泛型类型,但这在运行时失败了:Attribute?object

var attr = (MyTypedAttribute<object>?)myProp.GetCustomAttribute(typeof(MyTypedAttribute<>))

运行时错误:无法将类型为“MyNumberAttribute”的对象强制转换为类型“MyTypedAttribute”1[System.Object]”。

从本质上讲,我试图做的是获取属性并调用方法,捕获返回值。有什么办法可以做到这一点吗?ProcessValue

C# 泛型 转换 属性

评论

0赞 hsn-mnj 6/16/2023
你为什么要铸造它?当你得到反射时,投射它们是没有意义的!!找到它们后,你想怎么处理它们?!
0赞 devklick 6/16/2023
@HassanMonjezi 基类具有使用泛型类型的虚拟方法,派生类将重写该泛型类型。我想调用此方法并捕获返回值。我将更新问题以反映这一点。
2赞 NetMage 6/16/2023
反射就像一种病毒,它消除了类型安全。一旦你开始使用 Reflection,你往往不得不完全放弃类型安全。 是分配给它的编译时类型的编译时反映,因此只能有一个编译时类型。varattr
1赞 Serg 6/16/2023
您可以通过反射来获取属性。您甚至可以通过反思来打电话。但是这种调用的结果仍然是(因为反射在编译时无法知道它将调用哪个签名的哪个方法)。因此,您必须决定如何处理此非类型化值。ProcessValueobject
2赞 StriplingWarrior 6/16/2023
除了像其他人所提到的,在这种情况下没有从泛型类型中获得太多价值之外,感觉您可能在更一般意义上滥用了属性。将业务逻辑(如 ProcessValue 等方法)直接放在属性上并不常见,而且通常是不明智的。当您最终需要另一个类来处理值时会发生什么?依赖注入和单元可测试性消失了。考虑使用属性不做任何事情,而是使用元数据对类进行注释,并设置从这些注释到单独存在的特定行为的某种映射。

答:

1赞 Charlieface 6/16/2023 #1

可以创建非泛型基类

public class MyTypedAttribute<TValue> : MyUntypedAttribute
{ 
    public virtual TValue ProcessValue(object value)
    {
        // whatever
    }

    public override object ProcessValueObject(object value) =>
        ProcessValue(value);
}

public class MyUntypedAttribute : Attribute
{ 
    public abstract object ProcessValueObject(object value);
}

然后你可以做

var attr = myProp.GetCustomAttribute<MyUntypedAttribute>();

评论

0赞 StriplingWarrior 6/16/2023
好方法。我建议使用接口而不是基类。
0赞 devklick 6/16/2023
这几乎就是我最终想要的。感谢您的帮助