c# - 泛型可以改进这种设计吗?

标签 c# generics

下面模型(右侧)中的 PartyRoleConstraints 类是此问题的主题。

enter image description here

这个想法是,当客户端尝试将 Party 与 RoleType 相关联时,RoleType 会查看它是否有任何 Constraints 应该阻止给定的 Party 被关联。 Party 是 Person 和 Organization 的父类(super class)型。

这是我想要的完全通用的界面:

public interface IRoleConstraint<in T>
{
    Func<T, bool> IsSatisfied { get; }
    string UnsatisfiedDescription { get; }
    bool CanAddRole(T instance);
}

一个常见的约束是按类型。因此,如果我的角色类型是“丈夫”,那么我想确保 Party 实例是一个人。这是一些实现和测试用例,证明我可以做到这一点:

public class RoleConstraint<T> : IRoleConstraint<T>
{
    public RoleConstraint(Func<T, Boolean> isSatisfied, string unsatisfiedDescription) {
        if (isSatisfied == null) throw new ArgumentNullException("isSatisfied");
        if (unsatisfiedDescription == null) throw new ArgumentNullException("unsatisfiedDescription");

        IsSatisfied = isSatisfied;
        UnsatisfiedDescription = unsatisfiedDescription;
    }

    public Func<T, bool> IsSatisfied { get; protected set; }

    public string UnsatisfiedDescription { get; protected set; }

    public bool CanAddRole(T instance) { return IsSatisfied.Invoke(instance); }
}

public class PartyRoleConstraint : RoleConstraint<Party>
{
    public PartyRoleConstraint(Func<Party, bool> isSatisfied, string unsatisfiedDescription) : base(isSatisfied, unsatisfiedDescription) { }
}

public class PartyRoleConstrainedToType<TRequired> : PartyRoleConstraint where TRequired : Party
{
    private static readonly string _unsatisfiedDescription
        = string.Format("This role requires a Party instance to be a {0}", typeof(TRequired).Name);

    private static readonly Func<Party, bool> _isSatisfied = instance => instance.GetType().Equals(typeof(TRequired));

    public PartyRoleConstrainedToType() : base(_isSatisfied, _unsatisfiedDescription) { }
}

    [Test]
    public void Constraints_IfTypeConstraint_and_InstanceDoesNotMatch_False()
    {
        var sony = new Organization("Sony Corporation");
        var constraint = new PartyRoleConstrainedToType<Person>();
        _husbandRoleType.AddConstraint(constraint);
        Assert.That(_husbandRoleType.CanAddRole(sony), Is.False);
    }

我遇到的问题是,如果我想根据 Party 子类型的属性设置规则。例如,我希望丈夫的性别是男性。我可以通过 Actor 阵容做到这一点,因为:

    [Test]
    public void Constraints_IfConstraintConditionIsNotMet_False()
    {
        _husbandRoleType.AddConstraint(new PartyRoleConstrainedToType<Person>());
        Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.True);

        //**** here is the cast **** //
        var mustBeMale = new PartyRoleConstraint(p => ((Person)p).Gender == Gender.Male, "the husband must be male.");  

        _husbandRoleType.AddConstraint(mustBeMale);
        Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.False);
        _arthur.Gender = Gender.Male;
        Assert.That(_husbandRoleType.CanAddRole(_arthur), Is.True);
    }

问题(终于!)是:我可以使用泛型来避免强制转换吗?如果可以,如何避免?

最佳答案

是的,你可以去掉类型转换,但你必须在某处指定“Person”。在不了解您的要求和限制的情况下,很难提出这样做​​的“最佳地点”。一种选择是这样的:

var mustBeMale = PartyRoleConstraint.For<Person>( p => p.Gender == ...);

另一种选择是调整 PartyRoleConstrainedToType 以允许进一步的限制。示例可能如下所示:

var combinedConstraint = new PartyRoleConstrainedToType<Person>().MustSatisfy(p => p.Gender == ...);

如前所述:您必须在某处指定 Person,但有不同的选项可以创建不错的语法。什么是好,取决于您的要求和用例。

关于c# - 泛型可以改进这种设计吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6931493/

相关文章:

C# ChromiumWeb 浏览器 : Prevent control from stealing focus

c# - 如何跨类发布和订阅事件

c# - C# : restricting the type parameter to be a collection 中的泛型

专门化泛型协议(protocol)的 Swift 协议(protocol)

c# - 扩展方法、T的Func和T的List

java - 通配符泛型类型和泛型类型之间未经检查的转换

c# - 从 ComboBox 的模板设置 ComboBoxItem 的样式

C#, DETERMINE *if* a double 可以毫无损失地变成 int

c# - 如果启动时打开如何最小化到托盘? C-夏普

c# - 如何在foreach循环中实现通用输入参数属性名称