开发者

How can I make this generic interface more Typed?

Consider a class that uses role objects, maintaining a collection to do so. There may be constraints on whether a given role can be added, as well as action that should take place if it can be added.

The IRoleSpecication below is designed to separate the responsibility for the add decision and action away from the class maintaining the collection, so I have working code (ie, useful) that looks like the code sample below.

BUT I would like to make the IRoleSpecification.PreInsert handler use a generic type (TRole) instead of the object it currently uses. I tried adding a parameter for TRole, but my existing code wanted it to remain covariant while that method needed it to be invariant.

How can I do that?

Cheers,

Berryl

public interface IRoleSpecification<in T>
{

     bool CanAddRoleFor(T instance);

    /// <summary>
    /// Called when the newRole is about to be added to instance's collection of roles.
    /// </summary>
    /// <param name="instance">The instance.</param>
    /// <param name="newRole">The new role.</param>
    void OnPreInsert(T instance, object newRole);

    ...

}

public interface IEmployeeRoleSpecification<out TRole> : IRoleSpecification<EmployeeEx> where TRole : EmployeeRole
{
     bool IsJobRole { get; set; }
}

public abstract class EmployeeRoleSpecification<TRole> : ValueObject, IEmployeeRoleSpecification<TRole> 
    where TRole : EmployeeRole
{

    public virtual bool CanAddRoleFor(EmployeeEx employee) { return false; }

    public virtual void OnPreInsert(EmployeeEx instance, object newRole) {
        // jobRole helps enforce role constraints
        // employee may have only one job role for 'job' role specs
        if (IsJobRole) {
            instance.JobRole = (TRole) newRole;
        }
    }
    ....
}

MORE CODE

pu开发者_C百科blic class EmployeeRole : EmployeeEx
{
    private static readonly ISet<IEmployeeRoleSpecification<EmployeeRole>> _creationSpecs;

    static EmployeeRole() {
        _creationSpecs = new HashSet<IEmployeeRoleSpecification<EmployeeRole>>
                         {
                             new SalesmanRoleSpecification(),
                             new EngineerRoleSpecification(),
                             new ManagerRoleSpecification(),
                         };
    }
}


public class SalesmanRoleSpecification : EmployeeRoleSpecification<Salesman>
{
    public override bool CanAddRoleFor(EmployeeEx employee) { return _checkCanAddJobRole(employee); }

    public SalesmanRoleSpecification() { IsJobRole = true; }
}


Is there any reason you cannot declare IEmployeeRoleSpecification to be contravariant ?

Given the code you posted, this will compile:

public interface IEmployeeRoleSpecification<in TRole> : IRoleSpecification<EmployeeEx, EmployeeRole> where TRole : EmployeeRole
{
     bool IsJobRole { get; set; }
}

public abstract class EmployeeRoleSpecification<TRole> : IEmployeeRoleSpecification<TRole> 
    where TRole : EmployeeRole
{

    public virtual bool CanAddRoleFor(EmployeeEx employee) { return false; }

    public virtual void OnPreInsert(EmployeeEx instance, EmployeeRole newRole) {
        // jobRole helps enforce role constraints
        // employee may have only one job role for 'job' role specs
        if (IsJobRole) {
            instance.JobRole = newRole;
        }
    }

    public bool IsJobRole { get;set; }
}

public class EmployeeEx 
{
    public EmployeeRole JobRole { get;set;}
}

public class EmployeeRole { }

The reason why you might not be able to do this, is if IEmployeeRoleSpecification includes a member (that you omitted here), that exposes TRole (out-going) - because then the interface is covariant. The generic parameter cannot be both co-and contravariant.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜