23

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>();

これらの両方の呼び出しのスタイルには大きな欠点があると思います。最初のものは冗長な「タイプ/タイプの」構造に悩まされており、2番目のものはまったく意味がありません(動物でもキリンでもない動物のリストが必要ですか?)。

それで、私が望むことを達成する方法はありますか?そうでない場合、言語の将来のバージョンで可能でしょうか?(いつの日か、型引数に名前を付けるか、推論できない型引数を明示的に指定するだけでよいと思いますか?)

それとも私はばかげているだけですか?

4

7 に答える 7

33

なぜあなたがただ言わないのか分かりません:

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

これは私には完全に読めるようです。それは確かに私がそれに遭遇した場合に私を混乱させるよりも私にとってより簡単animals.NotOfType<Animal, Giraffe>()です...それはすぐに読めるので最初のものは私を混乱させることは決してありません。

流暢なインターフェースが必要な場合は、次の拡張メソッド述語を使用して、このようなこともできると思いますObject

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

どうですか

animals.NotOf(typeof(Giraffe));

または、ジェネリックパラメーターを2つのメソッドに分割することもできます

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

これは奇妙な提案のように思えるかもしれませんが、昔ながらの拡張メソッドは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>());

コレクションを2回列挙するという欠点がありますが(したがって、無限級数では使用できません)、新しいヘルパー関数が不要であり、意味が明確であるという利点があります。

私の実際のユースケースでは、.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 に答える