代码更新
为了修复过滤的错误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
被声明为常数。
概括
我正在尝试实现一个无限的 enumerable,但遇到了一些似乎不合逻辑的东西,并且暂时没有想法。我需要一些方向来完成代码,成为一个语义、逻辑、合理的设计。
整个故事
几个小时前我问过这个问题:
这可能不是一个好的实现模式。我正在尝试做的是以逻辑和语义的方式实现一个可枚举以呈现无穷大(我认为..)。我会把代码放在这篇文章的最后。
最大的问题是,它只是为了呈现无限可枚举,但它的枚举实际上没有任何意义,因为它没有真正的元素。
因此,除了为枚举提供虚拟元素之外,我可以想象有四个选项,其中三个导致
StackOverflowException
.抛出
InvalidOperationException
一次它会被枚举。public IEnumerator<T> GetEnumerator() { for(var message="Attempted to enumerate an infinite enumerable"; ; ) throw new InvalidOperationException(message); }
和3.在技术上是等价的,让栈溢出发生在真正溢出的时候。
public IEnumerator<T> GetEnumerator() { foreach(var x in this) yield return x; }
public IEnumerator<T> GetEnumerator() { return this.GetEnumerator(); }
(在 2 中描述)
不要等它发生,
StackOverflowException
直接扔。public IEnumerator<T> GetEnumerator() { throw new StackOverflowException("... "); }
棘手的事情是:
如果option 1
被应用,即对这个可枚举对象进行枚举,则成为无效操作。说这盏灯不是用来照明的不是很奇怪(尽管在我的情况下确实如此)。
如果应用option 2
or option 3
,也就是我们计划了栈溢出。它真的像标题一样吗,就在stackoverflow公平合理的时候?完全合乎逻辑和合理吗?
最后的选择是option 4
。然而,堆栈实际上并没有真正溢出,因为我们通过抛出一个假 StackOverflowException
的来防止它。这让我想起汤姆克鲁斯在扮演约翰安德顿时说过:“但它没有倒下。你抓住了它。你阻止它发生的事实并没有改变它将会发生的事实。 ”
一些避免不合逻辑问题的好方法?
代码是可编译和可测试的,注意其中之一应该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; } }