IEnumerable 的选项到 IEnumerable 的选项
IEnumerable of Options to Option of IEnumerable
我有一个获取 T 的 IEnumerable 并对其求值的第 3 方方法。
我想在我的 LINQ 评估语句(select,其中...)中引入 Option with exceptional values(either) 作为需要输入方法的值。
对于每个 T 元素,我希望有一个方法可以 return 转换元素或错误(将其保留为 deferred execution)并且如果错误是 returned 评估应该停在那里。 (从技术上讲,这可以通过抛出异常来实现,但这正是我使用 Option 试图避免的)
我想知道是否可以使用 LINQ 或更普遍的 C# 来实现这个概念?
如果无法实现,这会导致我用抛出异常完全替换代码中的选项,因为使用带有选项的 API 的客户端可能会出现同样的问题。
总而言之,这就是我要实现的目标:
这可能是一种可能的实施方法签名:
public Option<IEnumerable<T>,TError> Sequence<T,TError>(IEnumerable<Option<T,TError>> options)
其中:
应将 T 的 IEnumerable 保留为延迟执行
应该return发现第一个错误
发现错误时应该停止
** 最终方法需要 T 的 IEnumerable 来评估它(它可能是我无法访问的第 3 方方法)
而且我不想评估 IEnumerable 两次
在尝试解决这个问题一段时间后,感觉异常应该能够与任一 monad 模仿,我发布了一个 。
谢谢,根据马克的回答,这也证实了我对 "Either being isomorphic to C#/Java-style exceptions" 的怀疑。
我能够创建以下实现:
public static class LinqEitherExtension
{
public static IEnumerable<T> UntilException<T,TException>(
this IEnumerable<Option<T,TException>> enumerable,
Action<TException> errorHandler
)
{
return enumerable
.TakeWhile(e =>
{
e.MatchNone(errorHandler);
return e.HasValue;
})
.SelectMany(e => e.ToEnumerable());
}
}
public class Program
{
static void Main(string[] args)
{
var numbers = new List<int> {1, 2, 3, 4, 5};
ThirdPartyFunction(numbers.Select(CheckNumbers).UntilException(Console.WriteLine));
//returns:
//1
//2
//3 is exceptional number.
}
public static Option<int,string> CheckNumbers(int number)
{
return number == 3
? Option.None<int, string>("3 is exceptional number.")
: number.Some<int, string>();
}
//Cannot be accessed/altered
public static void ThirdPartyFunction(IEnumerable<int> numbers)
{
foreach (var number in numbers) Console.WriteLine(number.ToString());
}
}
注意:如果 ThirdPartyFunction 在使用可枚举后继续产生副作用(如 Console.WriteLine),这仍然会在异常抛出和使用错误作为 return 类型之间留下差距:
- 抛出异常的方法:也不会再执行任何副作用。
- 任何一种方法:都会让 ThirdPartyFunction 完成执行,使用函数输出的客户端可以忽略 return 值,但是内部发生的任何副作用仍然会执行。
对于我所追求的,这将完成工作。
我有一个获取 T 的 IEnumerable 并对其求值的第 3 方方法。 我想在我的 LINQ 评估语句(select,其中...)中引入 Option with exceptional values(either) 作为需要输入方法的值。
对于每个 T 元素,我希望有一个方法可以 return 转换元素或错误(将其保留为 deferred execution)并且如果错误是 returned 评估应该停在那里。 (从技术上讲,这可以通过抛出异常来实现,但这正是我使用 Option 试图避免的)
我想知道是否可以使用 LINQ 或更普遍的 C# 来实现这个概念?
如果无法实现,这会导致我用抛出异常完全替换代码中的选项,因为使用带有选项的 API 的客户端可能会出现同样的问题。
总而言之,这就是我要实现的目标:
这可能是一种可能的实施方法签名:
public Option<IEnumerable<T>,TError> Sequence<T,TError>(IEnumerable<Option<T,TError>> options)
其中:
应将 T 的 IEnumerable 保留为延迟执行
应该return发现第一个错误
发现错误时应该停止
** 最终方法需要 T 的 IEnumerable 来评估它(它可能是我无法访问的第 3 方方法) 而且我不想评估 IEnumerable 两次
在尝试解决这个问题一段时间后,感觉异常应该能够与任一 monad 模仿,我发布了一个
谢谢,根据马克的回答,这也证实了我对 "Either being isomorphic to C#/Java-style exceptions" 的怀疑。
我能够创建以下实现:
public static class LinqEitherExtension
{
public static IEnumerable<T> UntilException<T,TException>(
this IEnumerable<Option<T,TException>> enumerable,
Action<TException> errorHandler
)
{
return enumerable
.TakeWhile(e =>
{
e.MatchNone(errorHandler);
return e.HasValue;
})
.SelectMany(e => e.ToEnumerable());
}
}
public class Program
{
static void Main(string[] args)
{
var numbers = new List<int> {1, 2, 3, 4, 5};
ThirdPartyFunction(numbers.Select(CheckNumbers).UntilException(Console.WriteLine));
//returns:
//1
//2
//3 is exceptional number.
}
public static Option<int,string> CheckNumbers(int number)
{
return number == 3
? Option.None<int, string>("3 is exceptional number.")
: number.Some<int, string>();
}
//Cannot be accessed/altered
public static void ThirdPartyFunction(IEnumerable<int> numbers)
{
foreach (var number in numbers) Console.WriteLine(number.ToString());
}
}
注意:如果 ThirdPartyFunction 在使用可枚举后继续产生副作用(如 Console.WriteLine),这仍然会在异常抛出和使用错误作为 return 类型之间留下差距:
- 抛出异常的方法:也不会再执行任何副作用。
- 任何一种方法:都会让 ThirdPartyFunction 完成执行,使用函数输出的客户端可以忽略 return 值,但是内部发生的任何副作用仍然会执行。
对于我所追求的,这将完成工作。