Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在LINQ查询中对c#7元组进行空检查?_C#_Linq_C# 7.0 - Fatal编程技术网

如何在LINQ查询中对c#7元组进行空检查?

如何在LINQ查询中对c#7元组进行空检查?,c#,linq,c#-7.0,C#,Linq,C# 7.0,鉴于: 效果很好。我喜欢新语法更容易解释的意图,但我不确定在对发现的内容(或未发现的内容)采取行动之前如何对其进行null检查。值元组是值类型。它们不能为null,这就是编译器抱怨的原因。旧元组类型是引用类型 在这种情况下,FirstOrDefault()的结果将是ValueTuple的默认实例-所有字段都将设置为其默认值0 如果要检查默认值,可以将结果与ValueTuple的默认值进行比较,例如: class Program { private static readonly List

鉴于:


效果很好。我喜欢新语法更容易解释的意图,但我不确定在对发现的内容(或未发现的内容)采取行动之前如何对其进行null检查。

值元组是值类型。它们不能为null,这就是编译器抱怨的原因。旧元组类型是引用类型

在这种情况下,
FirstOrDefault()
的结果将是
ValueTuple
的默认实例-所有字段都将设置为其默认值0

如果要检查默认值,可以将结果与
ValueTuple
的默认值进行比较,例如:

class Program
{
    private static readonly List<Tuple<int, int, int>> Map = new List<Tuple<int, int, int>>()
    {
        new Tuple<int, int, int> (1, 1, 2),
        new Tuple<int, int, int> (1, 2, 3),
        new Tuple<int, int, int> (2, 2, 4)
    };

    static void Main(string[] args)
    {
        var result = Map.FirstOrDefault(w => w.Item1 == 4 && w.Item2 == 4);

        if (result == null)
            Console.WriteLine("Not found");
        else
            Console.WriteLine("Found");
    }
}
在C#7中可以将此调用简化为:

F#开发人员可以吹嘘,如果没有找到匹配项,他们有一个将返回
None

C#没有选项类型或Maybe类型(尚未),但也许(双关语)我们可以构建自己的:

if (myList.TryFirst(w => w.a == 4 && w.b == 1,out var result))
{
    Console.WriteLine(result);
}
除了更传统的:

var (found,value) =myList.TryPick(w => w.a == 4 && w.b == 1);

正如Panagiotis所写,你不能直接这么做。。。你可以“欺骗”一点:

var result=myList.TryPick(w => w.a == 4 && w.b == 1);
if (result.HasValue) {...}
使用
Where
最多取一个元素,并将结果放入长度为0-1的数组中

或者,您可以重复比较:

var result = Map.Where(w => w.a == 4 && w.b == 4).Take(1).ToArray();

if (result.Length == 0)
    Console.WriteLine("Not found");
else
    Console.WriteLine("Found");
如果您正在寻找,第二个选项将不起作用

var result = Map.FirstOrDefault(w => w.a == 4 && w.b == 4);

if (result.a == 4 && result.b == 4)
    Console.WriteLine("Not found");
在这种情况下,
FirstOrDefault()
返回的“默认”值具有
a==0
b==0

或者,您可以简单地创建一个“特殊的”
FirstOrDefault()
,它具有
out bool success
(如各种
TryParse
):

其他可能的扩展方法,
ToNullable()


请注意,
result
是一个
T?
,因此您需要执行
result.Value
以使用其值。

您的检查可以是:

var result = Map.Where(w => w.a == 4 && w.b == 4).ToNullable().FirstOrDefault();

if (result == null)

只需再添加一个选项来处理值类型和
FirstOrDefault
:使用
Where
并将结果强制转换为可为null的类型:

if (!Map.Any(w => w.a == 4 && w.b == 4))
{
    Console.WriteLine("Not found");
}
else
{
    var result = Map.First(w => w.a == 4 && w.b == 4);
    Console.WriteLine("Found");
}
var result=Map.Where(w=>w.a==4&&w.b==4)
.Cast().FirstOrDefault();
如果(结果==null)
控制台。写入线(“未找到”);
其他的
控制台。写入线(“找到”);
您甚至可以对其进行扩展:

var result = Map.Where(w => w.a == 4 && w.b == 4)
   .Cast<(int a, int b, int c)?>().FirstOrDefault();

if (result == null)
   Console.WriteLine("Not found");
else
   Console.WriteLine("Found");
公共静态类扩展{
公共静态T?StructFirstOrDefault(此IEnumerable items,Func谓词),其中T:struct{
返回items.Where(谓词).Cast().FirstOrDefault();
}
}

然后您的原始代码将被编译(假设您将
FirstOrDefault
替换为
StructFirstOrDefault
)。

ValueTuple是用于C#7元组的基础类型。它们不能为null,因为它们是值类型。您可以测试它们的默认值,但这实际上可能是一个有效值

此外,ValueTuple上未定义相等运算符,因此必须使用Equals(…)

static void Main(字符串[]args)
{
var result=Map.FirstOrDefault(w=>w.Item1==4&&w.Item2==4);
if(result.Equals(默认值(ValueTuple)))
控制台。写入线(“未找到”);
其他的
控制台。写入线(“找到”);
}

如果您确定您的数据集不包含
(0,0,0)
,那么正如其他人所说,您可以检查默认值:

static void Main(string[] args)
{
    var result = Map.FirstOrDefault(w => w.Item1 == 4 && w.Item2 == 4);

    if (result.Equals(default(ValueTuple<int, int, int>)))
        Console.WriteLine("Not found");
    else
        Console.WriteLine("Found");
}
或者,您可以使用一个库,该库提供一个
TryFirst
方法,如果不匹配,则返回一个“可能”类型的
none
,如果匹配,则返回该项:

class Program
{
    private static readonly List<(int a, int b, int c)> Map = 
        new List<(int a, int b, int c)>()
    {
        (1, 1, 2),
        (1, 2, 3),
        (2, 2, 4),
        (0, 0, 0)
    };

    static void Main(string[] args)
    {
        try
        {
            Map.First(w => w.a == 0 && w.b == 0);
            Console.WriteLine("Found");
        }
        catch (InvalidOperationException)
        {
            Console.WriteLine("Not found");
        }
    }
}
类程序
{
专用静态只读列表映射=
新名单()
{
(1, 1, 2),
(1, 2, 3),
(2, 2, 4),
(0, 0, 0)
};
静态void Main(字符串[]参数)
{
var result=Map.TryFirst(w=>w.a==0&&w.b==0);
Console.WriteLine(result.HasValue?“Found”:“notfound”);
}
}

以上大多数答案都意味着生成的元素不能是默认值(T),其中T是类/元组

一个简单的解决方法是使用以下方法:

class Program
{
    private static readonly List<(int a, int b, int c)> Map = 
        new List<(int a, int b, int c)>()
    {
        (1, 1, 2),
        (1, 2, 3),
        (2, 2, 4),
        (0, 0, 0)
    };

    static void Main(string[] args)
    {
        var result = Map.TryFirst(w => w.a == 0 && w.b == 0);
        Console.WriteLine(result.HasValue ? "Found" : "Not found");
    }
}
此示例使用C#7.1隐式元组名称(以及C#7的ValueTuple包),但如果需要,您可以显式地为元组元素指定名称,或者使用简单的
元组

您需要:

var result = Map
   .Select(t => (t, IsResult:true))
   .FirstOrDefault(w => w.t.Item1 == 4 && w.t.Item2 == 4);

Console.WriteLine(result.IsResult ? "Found" : "Not found");
(c#>7.1)

我是如何用c#7.3做到的

在C#7.3中,它非常干净:

T findme;
var tuple = list.Select((x, i) => (Item: x, Index: i)).FirstOrDefault(x => x.Item.GetHashCode() == findme.GetHashCode());

if (tuple.Equals(default))
    return;

...
var index = tuple.Index;

值元组是值类型。它们不能为null在这种情况下,默认值将是3个零的元组,而不是
null
。所以您可以检查它。@juharr但如果列表包含(0,0,0)项,这将中断,因此不太可靠。@Evk(0,0,0)在这种情况下与谓词不匹配,但在其他情况下可能会出现问题。@PanagiotisKanavos不正确。如果colleciton包含(0,0,0)且谓词与之匹配,该怎么办?然后,您必须使用
Any
进行预先检查,或者使用
Take(1).ToArray()
执行xanatos的技巧,以区分未找到和已找到,但恰好与默认值匹配。但是发布的LINQ查询显然不会在列表中找到一个元组,该元组的
a
b
值为4,那么我该如何验证呢?你会得到一个默认值——一个所有字段都设置为默认值的元组,即0。这可能是
映射
中的一个有效案例,我实际上并没有使用几个
int
,它只是作为一个示例。@Kritner那么问题是什么
FirstOrDefault
返回第一个值或默认值。正如
列表
将返回0(ints的默认值),在这种情况下,您将得到一个默认结构,即在C#7.1中所有字段都设置为默认值的ValueTuple,现在您可以只写:
如果(result.Equals(default))
,它将自动推断
默认值的类型。要使用C#7.1,您需要Visual Studio 2017的最新版本,并在项目构建设置中将C#版本设置为7.1(
Advanced…
)。我认为您不需要在第一个
if
中使用
结果=
。您的语法有点错误,第一个if应该是
if(Map.Any(…)
,b
var result = Map.Where(w => w.a == 4 && w.b == 4).ToNullable().FirstOrDefault();

if (result == null)
if (!Map.Any(w => w.a == 4 && w.b == 4))
{
    Console.WriteLine("Not found");
}
else
{
    var result = Map.First(w => w.a == 4 && w.b == 4);
    Console.WriteLine("Found");
}
var result = Map.Where(w => w.a == 4 && w.b == 4)
   .Cast<(int a, int b, int c)?>().FirstOrDefault();

if (result == null)
   Console.WriteLine("Not found");
else
   Console.WriteLine("Found");
public static class Extensions {
    public static T? StructFirstOrDefault<T>(this IEnumerable<T> items, Func<T, bool> predicate) where T : struct {
        return items.Where(predicate).Cast<T?>().FirstOrDefault();
    }
}
static void Main(string[] args)
{
    var result = Map.FirstOrDefault(w => w.Item1 == 4 && w.Item2 == 4);

    if (result.Equals(default(ValueTuple<int, int, int>)))
        Console.WriteLine("Not found");
    else
        Console.WriteLine("Found");
}
if (result.Equals(default(ValueTuple<int,int,int>))) ...
class Program
{
    private static readonly List<(int a, int b, int c)> Map = 
        new List<(int a, int b, int c)>()
    {
        (1, 1, 2),
        (1, 2, 3),
        (2, 2, 4),
        (0, 0, 0)
    };

    static void Main(string[] args)
    {
        try
        {
            Map.First(w => w.a == 0 && w.b == 0);
            Console.WriteLine("Found");
        }
        catch (InvalidOperationException)
        {
            Console.WriteLine("Not found");
        }
    }
}
class Program
{
    private static readonly List<(int a, int b, int c)> Map = 
        new List<(int a, int b, int c)>()
    {
        (1, 1, 2),
        (1, 2, 3),
        (2, 2, 4),
        (0, 0, 0)
    };

    static void Main(string[] args)
    {
        var result = Map.TryFirst(w => w.a == 0 && w.b == 0);
        Console.WriteLine(result.HasValue ? "Found" : "Not found");
    }
}
var result = Map
   .Select(t => (t, IsResult:true))
   .FirstOrDefault(w => w.t.Item1 == 4 && w.t.Item2 == 4);

Console.WriteLine(result.IsResult ? "Found" : "Not found");
if (result.Equals(default)) Console.WriteLine(...
T findme;
var tuple = list.Select((x, i) => (Item: x, Index: i)).FirstOrDefault(x => x.Item.GetHashCode() == findme.GetHashCode());

if (tuple.Equals(default))
    return;

...
var index = tuple.Index;
var result = Map.FirstOrDefault(w => w.a == 4 && w.b == 4);
if (result == default) {
    Console.WriteLine("Not found");
} else {
    Console.WriteLine("Found");
}