编辑:提出问题的另一种方式:
下面的代码来自我正在编写的Unity3D资产,所以c#的版本很老:“大多数但不完全是4.0”,谷歌告诉我。
下面的代码有效(模块化不可避免的错误),我的问题在于类型签名的表现力。问题在于VisitAnnotatedFields()方法的签名,特别是attrType参数 - 它总是由某些子类型的属性所支持。
在Java中,我将Java中的等效参数定义为“Class< Annotation>”为了告诉编译器调用者必须传递Annotation的子类型。
问题不是具体的注释,我以前在其他情况下遇到过这个问题;我只是在必要时通过检查和铸造来解决它。
有没有办法在C#中表达这个,或者我的所有类型引用都必须是“Type”,我需要编写一堆文档和代码来检查是否传递了正确的内容?
示例代码:
[AttributeUsage(AttributeTargets.Field)]
public class NotNullAttribute : Attribute {
}
class NullReferenceCheck : SceneGameObjectCheck {
public override IEnumerable<CheckFailure> Check(MonoBehaviour target){
var failures = new List<CheckFailure>();
ReflectionUtils.VisitAnnotatedFields(
target,
typeof(NotNullAttribute),
(FieldInfo field, Attribute attr) => {
// do the check for null value and add to failures
});
return failures;
}
}
public static void VisitAnnotatedFields(
MonoBehaviour target,
Type attrType,
Action<FieldInfo, Attribute> closure)
{
IEnumerable<FieldInfo> fieldInfos = target.GetAllFields();
foreach( var iField in fieldInfos ){
object[] customAttributes = iField.GetCustomAttributes(false);
foreach( var jAttr in customAttributes ){
if( jAttr.GetType().IsAssignableFrom(attrType) ){
closure.Invoke(iField, (Attribute) jAttr);
}
}
}
}
答案 0 :(得分:4)
虽然一般答案是否定的 - 但Type
没有编译类型检查 - 我相信你仍然可以使用泛型来达到你的目的,就像这样:
public static void VisitAnnotatedFields<TAttribute>(
MonoBehaviour target,
Action<FieldInfo, TAttribute> closure)
where TAttribute : Attribute
{
IEnumerable<FieldInfo> fieldInfos = target.GetAllFields();
foreach( var iField in fieldInfos ){
object[] customAttributes = iField.GetCustomAttributes(false);
foreach( var jAttr in customAttributes ){
if( jAttr.GetType().IsAssignableFrom(typeof(TAttribute)) ){
closure.Invoke(iField, (TAttribute) jAttr);
}
}
}
}
并像这样称呼它
ReflectionUtils.VisitAnnotatedFields(
target,
(FieldInfo field, NotNullAttribute attr) => {
// do the check for null value and add to failures
});
作为奖励,它将为您提供额外的强力内部封闭本身。
答案 1 :(得分:1)
如果我正确理解Java的Class<T>
(“Class
对象代表类型T
”,那么.NET中没有对应关系。
.NET无法在编译时限制 Type
的实例可能代表什么类型。你必须进行运行时检查:
// using System.Diagnostics.Contracts;
void Foo(Type type)
{
Contract.Requires(typeof(Attribute).IsAssignableFrom(type));
// the above allows `type` to represent sub-types of `Attribute` as well.
// if you want to allow only `Attribute`, change to `type == typeof(Attribute)`.
…
}