在方法签名中,针对一组派生类型的集合编写基类型的扩展方法

5

我想为一个对象集合编写一个扩展方法,该方法使用基类作为类型要求。我知道这不一定是做事情的最佳方式,但我很好奇,因为我对语言的细微差别很感兴趣。这个例子解释了我想做的事情。

public class Human { public bool IsHappy { get; set; } }
public class Man : Human { public bool IsSurly { get; set; } }
public class Woman : Human { public bool IsAgreeable { get; set; } }

public static class ExtMethods
{
    public static void HappinessStatus(this IEnumerable<Human> items)
    {
        foreach (Human item in items)
        {
            Console.WriteLine(item.IsHappy.ToString());
        }
    }
}

// then in some method, I wish to be able to do the following

List<Woman> females = RetreiveListElements(); // returns a list of Women
females.HappinessStatus(); // prints the happiness bool from each item in a collection

我唯一能够使扩展方法暴露的方式是创建一个Humans集合。只要我只引用基类型的成员,就可以在派生类型上调用这种类型的扩展方法吗?


它可以在 .Net 4 中正常工作,但在早期版本中可能无法正常运行。该问题的标签显示为 c#3.0。 - saus
1个回答

9

您的代码在使用C# 4编译器时实际上可以直接编译通过,因为该版本支持逆变类型参数

要使其与C# 3一起工作,您可以为IEnumerable<T>创建一个通用扩展方法,并对通用类型添加where T : Human约束,而不仅仅是针对IEnumerable<Human>

public static void HappinessStatus<T>(this IEnumerable<T> items) where T : Human
{
    foreach (T item in items)
    {
        Console.WriteLine(item.IsHappy.ToString());
    }
}

然后,您可以像描述的那样在List<Woman>集合上调用扩展方法。


这个确实可以工作,但我创建了一个通用的字符串列表,并且该方法暴露了一个字符串列表。是否有一种方法只在使用Human集合或Human派生类型集合时才公开此方法? - Nate
@Nate:我不这么认为。无论如何,你问题中的代码和我的答案都是有效的(我也测试了你的问题代码),如果你尝试在非人类列表上调用它们,它们都将无法编译。 - BoltClock
我现在明白为什么很多人反对这种类型的扩展方法,因为在集合上公开一个无法编译的方法是不好的形式。 - Nate
@Nate:我的错,你问题中的代码在编译为C# 4.0时可以工作。但是在C# 3.0下无法编译通过。很讽刺,因为我写答案的时候知道你正在寻找一个3.0的解决方案... - BoltClock
@Nate - “我创建了一个通用字符串列表,这个方法将其暴露给了一个字符串列表” <- 你的意思是什么?你是指它在智能感知中可用吗? - saus
@saus,是的,这正是我所说的,它在Intellisense中可用。 - Nate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接