简体   繁体   中英

What is the c# equivalent of Class<Annotation> from java?

EDIT: Another way to ask the question:

  • if " Class<Object> " in Java is equivalent to " Type " in C#
  • what's the equivalent of " Class<Annotation> "?

The code below is from a Unity3D asset I am writing, so the version of c# is quite old: " mostly but not entirely 4.0", Google tells me.

The code below works (modulo the inevitable bugs), my problem is with the expressiveness of the type signature. The problem is with the signature of the VisitAnnotatedFields() method, specifically the attrType parameter - which is always intended to by some sub-type of Attribute.

In Java, I would define the equivalent parameter in Java as "Class<Annotation>" in order to tell the compiler that the caller must pass a subtype of Annotation.

The question isn't specific Annotations, I've had this problem before in other situations; I've just worked around it by doing the check and casting as necessary.

Is there a way to express this in C#, or do all my type references have to be "Type" and I'll need to write a bunch of documentation and code to check that the right thing is passed?

Example Code:

[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);
      }
    }
  }
}

While in general answer is NO - there's no compile type check for Type - I believe you can still use generics for your purpose, like this one:

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);
        }
      }
    }
}

and call it like this

ReflectionUtils.VisitAnnotatedFields(
  target,
  (FieldInfo field, NotNullAttribute attr) => {
    // do the check for null value and add to failures
  });

Which as a bonus will provide you with additional strong type inside closure itself.

If I understand Java's Class<T> correctly ("a Class object that represents type T "), then there is no correspondence in .NET.

There is no way in .NET to restrict at compile-time what types an instance of Type may represent. You have to do a run-time check:

// 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)`. 
    …
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM