23

我正在尝试提出一个实现 for NotOfType,它具有可读的调用语法。NotOfType应该是补充OfType<T>并因此产生所有类型元素T

我的目标是实现一个方法OfType<T>,就像在这段代码的最后一行中一样:

public abstract class Animal {}
public class Monkey : Animal {}
public class Giraffe : Animal {}
public class Lion : Animal {}

var monkey = new Monkey();
var giraffe = new Giraffe();
var lion = new Lion();

IEnumerable<Animal> animals = new Animal[] { monkey, giraffe, lion };

IEnumerable<Animal> fewerAnimals = animals.NotOfType<Giraffe>();

但是,我无法提出支持该特定调用语法的实现。

这是我迄今为止尝试过的:

public static class EnumerableExtensions
{
    public static IEnumerable<T> NotOfType<T>(this IEnumerable<T> sequence, Type type)
    {
        return sequence.Where(x => x.GetType() != type);
    }

    public static IEnumerable<T> NotOfType<T, TExclude>(this IEnumerable<T> sequence)
    {
        return sequence.Where(x => !(x is TExclude));
    }
}

调用这些方法如下所示:

// Animal is inferred
IEnumerable<Animal> fewerAnimals = animals.NotOfType(typeof(Giraffe));

// Not all types could be inferred, so I have to state all types explicitly
IEnumerable<Animal> fewerAnimals = animals.NotOfType<Animal, Giraffe>();

我认为这两个电话的风格都存在重大缺陷。第一个具有冗余的“类型/类型”构造,而第二个则没有意义(我想要一个既不是动物也不是长颈鹿的动物列表?)。

那么,有没有办法完成我想要的?如果没有,在该语言的未来版本中是否有可能?(我在想也许有一天我们会命名类型参数,或者我们只需要显式提供无法推断的类型参数?)

还是我只是傻?

4

7 回答 7

33

我不知道你为什么不只是说:

animals.Where(x => !(x is Giraffe));

这对我来说似乎完全可读。它对我来说肯定比animals.NotOfType<Animal, Giraffe>()我遇到它会让我感到困惑......第一个永远不会让我感到困惑,因为它是立即可读的。

如果您想要一个流畅的界面,我想您也可以使用扩展方法谓词 on 做这样的事情Object

animals.Where(x => x.NotOfType<Giraffe>())
于 2010-12-30T03:21:12.453 回答
11

怎么样

animals.NotOf(typeof(Giraffe));

或者,您可以将泛型参数拆分为两种方法

animals.NotOf().Type<Giraffe>();

public static NotOfHolder<TSource> NotOf<TSource>(this IEnumerable<TSource> source);

public class NotOfHolder<TSource> : IHideObjectMembers {
    public IEnumerable<TSource> NotOf<TNot>();
}

此外,您需要决定是否也排除继承的类型。

于 2010-12-30T01:15:51.757 回答
5

这似乎是一个奇怪的建议,但是对于普通 old 的扩展方法IEnumerable呢?这将反映 的签名OfType<T>,并且还将消除冗余<T, TExclude>类型参数的问题。

我还要争辩说,如果您已经有一个强类型序列,那么没有什么理由需要特殊NotOfType<T>方法;从任意类型的序列中排除特定类型似乎更有用(在我看来)......或者让我这样说:如果你正在处理一个IEnumerable<T>,调用它是微不足道的Where(x => !(x is T));在这种情况下,类似方法的有用性NotOfType<T>变得更加可疑。

于 2010-12-30T02:21:59.290 回答
2

如果您要制定一种推理方法,则要一直进行推理。这需要每种类型的示例:

public static class ExtMethods
{
    public static IEnumerable<T> NotOfType<T, U>(this IEnumerable<T> source)
    {
        return source.Where(t => !(t is U));
    }
      // helper method for type inference by example
    public static IEnumerable<T> NotOfSameType<T, U>(
      this IEnumerable<T> source,
      U example)
    {
        return source.NotOfType<T, U>();
    }
}

List<ValueType> items = new List<ValueType>() { 1, 1.0m, 1.0 };
IEnumerable<ValueType> result = items.NotOfSameType(2);
于 2010-12-30T03:53:28.897 回答
2

我有一个类似的问题,并在寻找答案时遇到了这个问题。

我改为选择以下调用语法:

var fewerAnimals = animals.Except(animals.OfType<Giraffe>());

它的缺点是枚举了两次集合(因此不能与无限级数一起使用),但优点是不需要新的辅助函数,含义明确。

在我的实际用例中,我最后还添加了一个.Where(...).OfType<Giraffe>()长颈鹿也包括在内,除非它们满足仅对长颈鹿有意义的特定排除条件)

于 2017-02-28T16:51:45.727 回答
0

我刚试过这个,它的工作原理......

public static IEnumerable<TResult> NotOfType<TExclude, TResult>(this IEnumerable<TResult> sequence)
    => sequence.Where(x => !(x is TExclude));

我错过了什么吗?

于 2016-05-25T21:15:03.817 回答
0

你可能会考虑这个

public static IEnumerable NotOfType<TResult>(this IEnumerable source)
{
    Type type = typeof(Type);

    foreach (var item in source)
    {
       if (type != item.GetType())
        {
            yield return item;
        }
    }
}
于 2016-06-30T13:41:17.887 回答