C#通用约束无法正常工作

时间:2014-04-16 14:40:00

标签: c# generics constraints

我有以下代码:

public interface IEnrollment
{
    bool IsGood { get; set; }
}

public interface IEnrollmentToRegion
{
    int RegionId { get; set; }
}

public class ByRegion : IEnrollmentToRegion
{
    public int RegionId { get; set; }
}

public class Enrollment : IEnrollment
{
    public bool IsGood { get; set; }
    public ICollection<ByRegion> Regions { get; set; }
}

public class Main
{
    public void DoSomething()
    {
        var e = new Enrollment();
        if (isEnrolled(e, c => c.Any(l => l.RegionId == 10)))
        {

        }
    }

    private bool isEnrolled<T>(Enrollment enrollment, Func<ICollection<T>, bool> test) where T : IEnrollmentToRegion
    {
        return true;
    }
}

我要做的是创建方法isEnrolled,它接受IEnrollment类型的对象,在这个方法中我会做一堆检查,看看它是否返回true。我要检查的一件事是一组对象(在上面的例子中,它被简化为只有一个单独的类ByRegion类,但在我的实际中有多个Enrollment类,每个类都有它自己的独立集合,是不同类型的,但所有类型都有一个名为RegionId的属性。

所以我想传入一个函数来检查这些不同的集合,看看RegionId是否在集合中。我遇到的问题是我收到错误 c.Any(l => l.RegionId == 10))说它不知道RegionId是什么。事实上,当我击中。在l之后我没有得到任何智能感知。我不知道为什么我没有得到任何下拉列表,因为对T应该是IEnrollmentToRegion类型的限制,并且该类型上有RegionId。

1 个答案:

答案 0 :(得分:2)

您的问题是,ByRegionIEnrollmentToRegion时,ICollection<ByRegion>不是ICollection<IEnrollmentToRegion>。您可以使用反射测试:

//Returns true
return typeof(IEnrollmentToRegion).IsAssignableFrom(typeof(ByRegion));

//Returns false
return typeof(ICollection<IEnrollmentToRegion>).IsAssignableFrom(typeof(ICollection<ByRegion>));

因此,您无法指定T并让类型推断为您处理。实际上,即使您明确指定了类型,例如:

isEnrolled<IEnrollmentToRegion>(e, c => c.Any(l => l.RegionId == 10))

您发现,一旦您尝试撰写isEnrolled<T>的实际内容,您就会遇到问题。

以下是您的代码的更新版本:

public interface IEnrollment<T> where T:IEnrollmentToRegion
    {
        bool IsGood { get; set; }
        ICollection<T> Regions { get; set; }
    }

    public interface IEnrollmentToRegion
    {
        int RegionId { get; set; }
    }

    public class ByRegion : IEnrollmentToRegion
    {
        public int RegionId { get; set; }
    }

    public class Enrollment : IEnrollment<ByRegion>
    {
        public bool IsGood { get; set; }
        public ICollection<ByRegion> Regions { get; set; }
    }

    public class Main
    {
        public void DoSomething()
        {
            var e = new Enrollment();
            e.Regions = new List<ByRegion>() { new ByRegion { RegionId = 10 } };

            if (isEnrolled(e, c => c.Any(l => l.RegionId == 10)))
            {
                //This line gets hit
            }
        }

        private bool isEnrolled<T>(IEnrollment<T> enrollment, Func<ICollection<T>, bool> test) where T : IEnrollmentToRegion
        {
            return test(enrollment.Regions);
        }