我正在try 实现一个函数,它过滤掉一些条目,并取由具体函数映射的最小值,然后要么返回由它判断的最小值,要么在过滤掉所有元素后得到null:

public readonly record struct PdfVerticalPos(float Raw_LessIsBelow)
{
}

public readonly record struct AxisAlignedRenderingBox
{
    public AxisAlignedRenderingBox(PdfVerticalPos upMost, PdfVerticalPos downMost, float leftMostRaw, float rightMostRaw)
    {
        this.UpMost = upMost;
        this.DownMost = downMost;
        this.LeftMost = leftMostRaw;
        this.RightMost = rightMostRaw;
    }
}

private static string? findTheBottomByCondition(IEnumerable<(AxisAlignedRenderingBox, string)> detectedStrings,
    float leftMostMin, float leftMostMax, Func<(AxisAlignedRenderingBox, string), bool> selectingPredicate)
{
    return detectedStrings
        .Where(selectingPredicate)
        .Where(tuple => leftMostMin <= tuple.Item1.LeftMost && tuple.Item1.LeftMost <= leftMostMax)
        .MinBy(tuple => tuple.Item1.UpMost.Raw_LessIsBelow).Item2;
}

internal void someCallSite() {
    var detectedStrings = whatever();
    var found = findTheBottomByCondition(detectedStrings, 60, 65,
                    tuple => tuple.Item1.UpMost.Raw_LessIsBelow >= baseY);
    // do whatever
}

然而,当呼叫MinBy时,它会抛出InvalidOperationException.当我判断原因时,我发现文档上写着"如果TSource是一个原始类型并且源序列为空,则抛出InvalidOperationException".不确定"基本类型"是什么意思,因为元组显然不是opposed to integers的基本类型.

因此,我重写了findTheBottomByCondition条,如下所示:

private static string? findTheBottomByCondition(IEnumerable<(AxisAlignedRenderingBox, string)> detectedStrings,
    float leftMostMin, float leftMostMax, Func<(AxisAlignedRenderingBox, string), bool> selectingPredicate) {
    
    var valueTuples = detectedStrings.ToList();
    var a = valueTuples
            .Where(selectingPredicate)
            .Count(tuple => leftMostMin <= tuple.Item1.LeftMost && tuple.Item1.LeftMost <= leftMostMax);
    if (a > 0)
    {
        return valueTuples
            .Where(selectingPredicate)
            .Where(tuple => leftMostMin <= tuple.Item1.LeftMost && tuple.Item1.LeftMost <= leftMostMax)
            .MinBy(tuple => tuple.Item1.UpMost.Raw_LessIsBelow).Item2;
    }
    else
    {
        return null;
    }
}

虽然它工作正常,但不是很优雅,只是避免了异常.我希望它返回null,如果没有找到它,不管它是不是"原始类型",你有什么 idea 吗?我想我可以通过catch-ING InvalidOperationException来实现它,但我不喜欢这种方式,也不喜欢目前大多数复制粘贴和糟糕的实现.

推荐答案

文档应该说,如果TSourcenon-nullable类型,而不仅仅是一个原始类型,MinBy会抛出InvalidOperationException.

为了使MinBy返回null而不是引发InvalidOperationException,源序列必须支持null个值.您可以使用强制转换扩展方法将元组转换为可为空的元组:

.Where(...)
.Cast<(AxisAlignedRenderingBox, string)?>()
.MinBy(...)

或者你可以定义一个扩展方法来推断正确的类型:

public static class EnumerableExtensions
{
    public static IEnumerable<TSource?> AsNullable<TSource>(this IEnumerable<TSource> source)
        where TSource : struct
    {
        return source.Cast<TSource?>();
    }
}

并这样称呼它:

.Where(...)
.AsNullable()
.MinBy(...)

因为MinBy的参数现在是一个可以为空的元组,而不仅仅是一个元组,所以您必须使用Value属性:

.MinBy(tuple => tuple!.Value.Item1.UpMost.Raw_LessIsBelow)

最后,由于MinBy现在可以返回null,因此在访问结果元组的Item2属性之前,您需要使用条件为空的?.操作符.

Csharp相关问答推荐

Blazor:用参数创建根路径

使用GeneratedComInterfaceProperty的.NET 8 COM类对于VB 6/SYS或ALEViewer不可见

获取ASP.NET核心身份认证cookie名称

TDLib与机器人共享电话号码

从应用程序图API调用访问所有者字段

自动映射程序在GroupBy之后使用项目

如何在C#中从正则表达式中匹配一些数字但排除一些常量(也是数字)

MS Graph v5.42.0:在寻呼消息时更改页面大小

Rx.Net窗口内部可观测数据提前完成

如何使用C#获取FireStore中的列表输出文档

如何在ASP.NET Core8中启用REST应用程序的序列化?

为什么无法将对象转换为泛型类型

如何使用自定义负载均衡器管理Ocelot负载均衡器中的多线程和批读取

反序列化私有成员

用于管理System.Text.Json中的多态反序列化的自定义TypeInfoResolver

为什么@rendermode Interactive Auto不能在.NET 8.0 Blazor中运行?

FakeItEasy自动嘲弄内容

为什么当我try 为玩家角色设置动画时,没有从文件夹中拉出正确的图像?

默认架构不存在EF核心迁移

无法通过服务控制台启动.NET Core 6.0服务(错误1053)