如何将类型为int[]的数组转换为int?[]?

3

我正在使用linq查询输出一个int数组。但我需要将其传递到只接受int?[]的方法中。

因此,在搜索将int[]转换为int?[]的方法时,我发现了一个似乎可行的解决方案here

以下代码是一个简化的示例,展示了什么起作用和不起作用。

using System;
using System.Collections.Generic;
using System.Web;
using System.Linq;

namespace ConsoleApp
{
    class Program
    {
        static void Main(string[] args)
        {
            // working...
            int[] vids1 = new[] { "", "1", "2", "3" }
                .Where(x => !String.IsNullOrWhiteSpace(x))
                .Select(x => Convert.ToInt32(x))
                .ToArray();

            foreach(int i in vids1) 
            {
                System.Diagnostics.Debug.WriteLine(i.ToString());
            }

            // not working...
            int?[] vids2 = new[] { "", "1", "2", "3" }
                .Where(x => !String.IsNullOrWhiteSpace(x))
                .Select(x => Convert.ToInt32(x))
                .ToArrayOrNull();
        }
    }

    public static class IEnumerableExtensions
    {
        public static T?[] ToArrayOrNull<T>(this IEnumerable<T> seq)
        {
            var result = seq.ToArray();

            if (result.Length == 0)
                return null;

            return result;
        }
    }
}

我已经尝试使用这个扩展方法来获取int?[]类型,但是目前还没有成功。

我该如何让我的IEnumerable扩展方法ToArrayOrNull返回可空类型?


你似乎混淆了传递可空整数数组和返回空数组。你想要实现什么? - Scottie
@PoweredByOrange where T : struct 就能完成这个任务。 - DavidG
5个回答

5

int?[]是一个int?类型的数组。你只需要改变Select中的lambda表达式,让它返回一个int?类型:

int?[] vids2 = new[] { "", "1", "2", "3" }
    .Where(x => !String.IsNullOrWhiteSpace(x))
    .Select(x => (int?)Convert.ToInt32(x))
    .ToArray();

如果您已经有一个int[],您可以使用Cast()将元素转换为int?

int[] ints = { 1, 2, 3 };
int?[] nullableInts = ints.Cast<int?>().ToArray();

3
不要先做错事,然后再进行修补。直接做正确的事情。你知道需要一个 int?[],那么就创建一个 int?[]。不要先创建一个 int[] 然后再加以修补。你或许可以让它工作,但这是没有意义的复杂化。
int?[] vids1 = new[] { "", "1", "2", "3" }
    .Where(x => !String.IsNullOrWhiteSpace(x))
    .Select(x => (int?) Convert.ToInt32(x))
    .ToArray();

我强烈建议你不要试图让你的ToArrayOrNull工作,原因是它根本不能做你说它应该做的事情。你可以使它工作,但在编码之前必须了解应该发生什么。如果你现在不需要它,就把它留给以后吧,当你稍后回头看时,你可能会突然看到它。


我知道我忽略了什么。感谢你纠正我。 - ooXei1sh
1
@ooXei1sh 感谢您的编辑建议。我加入了最后一句是因为当我没有它时重新阅读我的答案时,感觉自己有点傻。 :) 不过我很高兴您理解我的意思。 - user743382

2
这个扩展方法ToArrayOrNull不会改变内容的类型。 seqT类型的IEnumerableresultT类型的数组(有时你可以将其返回为null,但仍然是一个T类型的数组)。
如果你真的想将IEnumerable<T>转换为IEnumerable<T?>(或者T?类型的数组), 你应该对类型参数加以限制(它应该是struct,即值类型,不能为null),并且要对每个项进行转换,而不是整个结果,类似于这样:
    public static T?[] ToArrayOfNullable<T>(this IEnumerable<T> seq)
        where T : struct
    {
        return seq.Select(val => (T?)val).ToArray();
    }

尽管我会在此处返回一个 IEnumerable<T?> 并稍后转换为数组,以保持该方法简单。

@M.kazemAkhgary,你是正确的,我会更改的。 - joranvar

1
使用Cast<>和类型约束使T成为struct,这样怎么样?
public static IEnumerable<T?> ToArrayOrNull<T>(this IEnumerable<T> seq)
    where T : struct
{
    if (seq.Count() == 0)
        return null;

    return seq.Cast<T?>().ToArray();
}

1

我知道这不是你问题的正确答案,但有一个略微不同的解决方案 - 如果你想保持顺序和集合长度。

public static class EnumerableExtensions
{
    public delegate bool ParseDelegate<T>(string input, out T value) where T : struct;

    public static T?[] ToNullable<T>(this string[] values, ParseDelegate<T> parseMethod) where T : struct
    {
        IEnumerable<T?> cos = values.Select(s =>
        {
            T result;
            if (parseMethod(s, out result))
            {
                return (T?)result;
            }

            return null;
        });

        return cos.ToArray();
    }
}

使用方法:

var cos = new[] { "1", "", "3", "True" };
int?[] eee= cos.ToNullable<int>(int.TryParse); // 1, null, 3, null
float?[] ada = cos.ToNullable<float>(float.TryParse); // 1, null, 3, null
bool?[] asd3 = cos.ToNullable<bool>(bool.TryParse); // null, null, null, true

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接