Berryl
Berryl

Reputation: 12833

use reflection to get type from an interface

Given the following types

private class MyTestDummyClassValidationDef : ValidationDef<MyTestDummyClass>
    {
        ...
    }

public class ValidationDef<T> : IValidationDefinition<T>, IConstraintAggregator, IMappingSource where T : class        
{        }

public interface IMappingSource
{
    IClassMapping GetMapping();
}

public interface IClassMapping
{
    Type EntityType { get; }
    ...
}

At configuration time I know all of the ValidationDefinitions; "MyTestDummyClassValidationDef " above is an example of such a definition.

If you follow the inheritance / implementation trail, at the end is an EntityType that is exposed by IClassMapping.

As part of my validation infrastructure, various objects may be asked to validate themselves. The objects may or may not have a ValidationDef defined for them, either because validation doesn't apply fo that object or the definition hasn't been written yet. If an object is asked to validate itself and there is no definition then a runtime error will occur.

SO, what I am trying to is have a list of EntityTypes that I can use to check at runtime. If the object being asked to validate itself is not on the list then I can avoid the runtime error that would otherwise occur.

How might I do that?

Cheers,
Berryl

the code I was looking for

public EntityValidator(ValidatorEngine validatorEngine, IEnumerable<Type> defTypes) {

ValidationDefs = new List<Type>();
foreach (var type in defTypes) 
{
    if (type.BaseType.GetGenericTypeDefinition() != typeof(ValidationDef<>)) continue;

    var mappingSource = (IMappingSource) Activator.CreateInstance(type);
    var entityType = mappingSource.GetMapping().EntityType;
    ValidationDefs.Add(entityType);
}

Upvotes: 0

Views: 3262

Answers (2)

Nikola Anusev
Nikola Anusev

Reputation: 7088

Ok, after clarification (see comments to the question), here is the way to find all implementations of ValidationDef in an assembly and create a list of values of their EntityType properties:

List<Type> entityTypes = new List<Type>();

foreach (Type type in Assembly.GetExecutingAssembly().GetTypes())
{
    if (InheritsFromValidationDef(type))
    {
        IMappingSource mappingSource = (IMappingSource)Activator.CreateInstance(type);
        entityTypes.Add(mappingSource.GetMapping().EntityType);
    }
}

private static bool InheritsFromValidationDef(Type type)
{
    Type baseType = type.BaseType;
    bool result = baseType != null && 
                  baseType.IsGenericType &&
                  baseType.GetGenericTypeDefinition() == typeof(ValidationDef<>);
    return result;
}

Few points to note here:

  • Types in the current assembly are being examined (Assembly.GetExecutingAssembly). Obviously, this may or may not be sufficient for your scenario.
  • BaseType returns the direct parent of the type being examined. Again, you may want to examine the type hierarchy a bit further up the inheritance chain.
  • It is assumed that all examined types have a parameterless constructor. Otherwise, Activator.CreateInstance bit won't work.

Although it is certainly possible to do what you ask, I would like to strongly emphasize that it is very likely that there is much, much simpler solution to your validation needs. From what you've told us of your solution, it is obvious that it has a few serious flaws:

  • How is it possible that you can invoke validation on objects that cannot be validated? I think that this is the root of all your sorrows.
  • Your inheritance hierarchy is far too complex and hard to understand. Why do you need so many interfaces?

Perhaps try to create a separate question detailing your validation needs. I am sure that a simpler solution can be found.

Upvotes: 0

O. R. Mapper
O. R. Mapper

Reputation: 20722

If I understand this correctly, you want to call an explicit interface implementation of a method, i.e. a method that implements an interface method and that is only visible in the interface itself, not in the class.

In order to do so, first retrieve the Type object for IClassMapping (with typeof(IClassMapping)). On that object, call GetProperty to retrieve a PropertyInfo instance for the EntityType property.

You should then be able to retrieve the property value by invoking PropertyInfo.GetValue on your ValidationDef<T> instance.

Use, for example, this method:

Type GetEntityType(ValidationDef<T> def)
{
    PropertyInfo prop = typeof(IClassMapping).GetProperty("EntityType");
    return (Type)prop.GetValue(def, null);
}

Upvotes: 1

Related Questions