16

コードが更新されました

フィルタリングされた のバグを修正するためInterminableに、次のコードが更新され、元のコードにマージされます。

public static bool IsInfinity(this IEnumerable x) {
    var it=
        x as Infinity??((Func<object>)(() => {
            var info=x.GetType().GetField("source", bindingAttr);
            return null!=info?info.GetValue(x):x;
        }))();

    return it is Infinity;
}

bindingAttr定数として宣言されています。


  • 概要

    無限の列挙可能なを実装しようとしていますが、非論理的な何かに遭遇し、一時的にアイデアが不足しています。コードを完成させ、セマンティックで論理的で合理的なデザインにするための方向性が必要です。

  • 一部始終

    私は数時間前に質問しました:

    無限列挙可能はまだ「列挙可能」ですか?

    これは、実装の適切なパターンではない可能性があります。私がやろうとしているのは、論理的かつセマンティックな方法で、無限を表す列挙可能なものを実装することです(私は..と思いました)。この投稿の最後にコードを配置します。

    大きな問題は、それは無限の列挙可能なものを提示するためだけのものですが、その列挙には実際の要素がないため、実際には意味がありません。

    したがって、列挙にダミー要素を提供する以外に、私が想像できる 4 つのオプションがあり、そのうちの3 つStackOverflowException.

    1. InvalidOperationException列挙されるときに一度投げます。

      public IEnumerator<T> GetEnumerator() {
          for(var message="Attempted to enumerate an infinite enumerable"; ; )
              throw new InvalidOperationException(message);
      }
      
    2. と 3. は技術的に同等です。実際にオーバーフローしたときにスタック オーバーフローが発生するようにします。

      public IEnumerator<T> GetEnumerator() {
          foreach(var x in this)
              yield return x;
      }
      
      public IEnumerator<T> GetEnumerator() {
          return this.GetEnumerator();
      }
      
    3. (2で説明)

    4. それが起こるのを待たずに、StackOverflowException直接投げてください。

      public IEnumerator<T> GetEnumerator() {
          throw new StackOverflowException("... ");
      }
      

トリッキーなことは次のとおりです。

が適用された場合option 1、つまり、この列挙可能なものを列挙すると、無効な操作になります。このランプが照明に使用されていないというのは奇妙ではありませんか(私の場合はそうですが)。

option 2またはoption 3が適用された場合、つまり、スタック オーバーフローを計画しました。stackoverflowが公正で賢明な場合、それは本当にタイトルのとおりですか? 完全に論理的で合理的ですか?

最後の選択肢はoption 4. ただし、実際にはスタックが実際にオーバーフローするわけではありませ StackOverflowException。これは、トム・クルーズが演じたとき、ジョン・アンダートンが次のように言ったことを思い出させます

非論理的な問題を回避する良い方法はありますか?


コードはコンパイル可能でテスト可能です。コンパイル前に to の 1 つを定義する必要があることに注意してOPTION_1くださいOPTION_4

  • 簡単なテスト

    var objects=new object[] { };
    Debug.Print("{0}", objects.IsInfinity());
    var infObjects=objects.AsInterminable();
    Debug.Print("{0}", infObjects.IsInfinity());
    
  • クラス

    using System.Collections.Generic;
    using System.Collections;
    using System;
    
    public static partial class Interminable /* extensions */ {
        public static Interminable<T> AsInterminable<T>(this IEnumerable<T> x) {
            return Infinity.OfType<T>();
        }
    
        public static Infinity AsInterminable(this IEnumerable x) {
            return Infinity.OfType<object>();
        }
    
        public static bool IsInfinity(this IEnumerable x) {
            var it=
                x as Infinity??((Func<object>)(() => {
                    var info=x.GetType().GetField("source", bindingAttr);
                    return null!=info?info.GetValue(x):x;
                }))();
    
            return it is Infinity;
        }
    
        const BindingFlags bindingAttr=
            BindingFlags.Instance|BindingFlags.NonPublic;
    }
    
    public abstract partial class Interminable<T>: Infinity, IEnumerable<T> {
        IEnumerator IEnumerable.GetEnumerator() {
            return this.GetEnumerator();
        }
    
    #if OPTION_1
        public IEnumerator<T> GetEnumerator() {
            for(var message="Attempted to enumerate an infinite enumerable"; ; )
                throw new InvalidOperationException(message);
        }
    #endif
    
    #if OPTION_2
        public IEnumerator<T> GetEnumerator() {
            foreach(var x in this)
                yield return x;
        }
    #endif
    
    #if OPTION_3
        public IEnumerator<T> GetEnumerator() {
            return this.GetEnumerator();
        }
    #endif
    
    #if OPTION_4
        public IEnumerator<T> GetEnumerator() {
            throw new StackOverflowException("... ");
        }
    #endif
    
        public Infinity LongCount<U>(
            Func<U, bool> predicate=default(Func<U, bool>)) {
            return this;
        }
    
        public Infinity Count<U>(
            Func<U, bool> predicate=default(Func<U, bool>)) {
            return this;
        }
    
        public Infinity LongCount(
            Func<T, bool> predicate=default(Func<T, bool>)) {
            return this;
        }
    
        public Infinity Count(
            Func<T, bool> predicate=default(Func<T, bool>)) {
            return this;
        }
    }
    
    public abstract partial class Infinity: IFormatProvider, ICustomFormatter {
        partial class Instance<T>: Interminable<T> {
            public static readonly Interminable<T> instance=new Instance<T>();
        }
    
        object IFormatProvider.GetFormat(Type formatType) {
            return typeof(ICustomFormatter)!=formatType?null:this;
        }
    
        String ICustomFormatter.Format(
            String format, object arg, IFormatProvider formatProvider) {
            return "Infinity";
        }
    
        public override String ToString() {
            return String.Format(this, "{0}", this);
        }
    
        public static Interminable<T> OfType<T>() {
            return Instance<T>.instance;
        }
    }
    
4

4 に答える 4

4

あなたがリンクした他の投稿で述べたように、無限の列挙はC#が列挙するのに完全に理にかなっており、人々が決して終わらない列挙子を書く現実世界の例がたくさんあります(私の頭から飛び出す最初のことはランダムですナンバジェネレータ)。

したがって、数学の問題には、特別な値 (無数の交点) を定義する必要がある特定のケースがあります。通常、それは単純な静的定数を使用する場所です。いくつかの静的定数 IEnumerable を定義し、それに対してテストして、アルゴリズムが結果として「無限の交差」を持っているかどうかを確認するだけです。

現在の質問に具体的に答えるには、実際のスタックオーバーフローを決して引き起こさないでください。これは、コードのユーザーに対して行うことができる最も厄介なことです。これはキャッチできず、すぐにプロセスを終了します (おそらく唯一の例外は、接続されたインストルメント デバッガー内で実行している場合です)。

あるとしてもNotSupportedException、他の場所で使用されている which を使用して、一部のクラスが機能をサポートしていないことを通知します (たとえば、読み取り専用の場合、 ICollections がこれをスローする可能性Remove()があります)。

于 2013-05-30T10:32:44.840 に答える
3

私の理解が正しければ、無限という言葉は紛らわしいです。列挙可能かどうかのどちらかであるモナドが必要だと思います。しかし、今のところ無限に固執しましょう。

これを C# で実装する良い方法は思いつきません。これを実装できるすべての方法は、C# ジェネレーターと統合されません。

C# generatorでは、有効な値のみを発行できます。したがって、これが無限の列挙可能であることを示す方法はありません。無限であることを示すためにジェネレーターから例外をスローするという考えは好きではありません。それが無限であることを確認するには、毎回try-catchを実行する必要があるためです。

ジェネレーターをサポートする必要がない場合は、次のオプションが表示されます。

  1. センチネル列挙可能を実装します。

    public class InfiniteEnumerable<T>: IEnumerable<T> {
        private static InfiniteEnumerable<T> val;
    
        public static InfiniteEnumerable<T> Value {
            get {
                return val;
            }
        }
    
        public IEnumerator<T> GetEnumerator() {
            throw new InvalidOperationException(
                "This enumerable cannot be enumerated");
        }
    
        IEnumerator IEnumerable.GetEnumerator() {
            throw new InvalidOperationException(
                 "This enumerable cannot be enumerated");
        }
    }
    

    使用例:

    IEnumerable<int> enumerable=GetEnumerable();
    
    if(enumerable==InfiniteEnumerable<int>.Value) {
        // This is 'infinite' enumerable.
    }
    else {
        // enumerate it here.
    }
    
  2. Infinitable<T>ラッパーを実装します。

    public class Infinitable<T>: IEnumerable<T> {
        private IEnumerable<T> enumerable;
        private bool isInfinite;
    
        public Infinitable(IEnumerable<T> enumerable) {
            this.enumerable=enumerable;
            this.isInfinite=false;
        }
    
        public Infinitable() {
            this.isInfinite=true;
        }
    
        public bool IsInfinite {
            get {
                return isInfinite;
            }
        }
    
        public IEnumerator<T> GetEnumerator() {
            if(isInfinite) {
                throw new InvalidOperationException(
                    "The enumerable cannot be enumerated");
            }
    
            return this.enumerable.GetEnumerator();
        }
    
        IEnumerator IEnumerable.GetEnumerator() {
            if(isInfinite) {
                throw new InvalidOperationException(
                     "The enumerable cannot be enumerated");
            }
    
            return this.enumerable.GetEnumerator();
        }
    }
    

    使用例:

    Infinitable<int> enumerable=GetEnumerable();
    
    if(enumerable.IsInfinite) {
        // This is 'infinite' enumerable.
    }
    else {
        // enumerate it here.
        foreach(var i in enumerable) {
        }
    }
    
于 2013-05-25T16:29:10.477 に答える