Berryl
Berryl

Reputation: 12863

Dealing with a Generic Type cast

I have a generic type (RoleEntity) that may or may not implement an interface that is also generic (IActor). Background on the design is below, but the short story is that a RoleEntity is a role that maybe assumed by an Actor and that RoleEntity may optionally be an IActor with it's own Roles.

So if I want to access the Roles of a an Actor's role, I can think of two options

  1. Cast the role safely to an Actor{T}. This is what I would do if I wasn't casting one generic to another; it seems the only way to do this is with some non-trivial reflection.
  2. Use dynamic.

The code below is a bastardized mix of both. I am using reflection but not far enough to actually figure out the exact IActor{T}. Then because I have an indeterminate type I use IEnumerable{dynamic}. It doesn't feel like good code but I don't know how to do better.

Can someone present some cleaner code?

static void GetRoleHeirarchyString<T>(IActor<T> actor)
    where T : Entity, IActor<T> 
{
    foreach (var role in actor.AllRoles) {
        // do something with the Role;

        // trivial reflection
        var type = role.GetType();
        var pi = type.GetProperty("AllRoles");
        if (pi == null)
            continue;
        var roles = pi.GetValue(role, null) as IEnumerable<dynamic>;    // dynamic
        foreach (var r in roles) {
            // do something with the Role;
        }
    }
}

Backround

Below are two interfaces that are part of a solution implementing Roles. In this design, a class that might be expressed as one or more Roles is called an Actor. The class that is expressing a Role (called a 'Role'!) uses an instance of the Actor to forward properties of interest from the Actor. So for example, if a Person class is an Actor for several roles in an application )ie, Student, Mother, and Employee) then each Role might use an instance of the Person to have a common Name property that is based on the Person.

Roles may or may not also be Actors; an Employee may be a ProjectManager or even a Buyer of something her employers sells. But a Student may just be a role for a Person and not an Actor.

public class RoleEntity<T> : Entity where T : Entity, IActor<T>
{
    public T Actor { get; protected set; }
    ...
}

public interface IActor<T> where T : Entity, IActor<T>
{
    bool AddRole(IRoleFor<T> role);
    bool RemoveRole(IRoleFor<T> role);
    bool HasRole(IRoleFor<T> role);
    IEnumerable<IRoleFor<T>> AllRoles { get; }
}

Upvotes: 0

Views: 138

Answers (1)

Sergey Zyuzin
Sergey Zyuzin

Reputation: 3834

Sometimes it is possible to define non-generic interface IRoleEntity and have your RoleEntity<T>implement IRoleEntity.

If you declare a method IRole.DoSomethingWithTheRole, then you can implement it in RoleEntity<T>. And you can call it without knowing exact RoleEntity<T> type thanks to polymorphism.

Same trick you may want to do with IActor<T> inheriting IActor.

It doesn't always make sense, but I don't have enough understanding of your problem.

Upvotes: 1

Related Questions