为什么我需要用这个简单的 LINQ 表达式来引用 System.Numerics?

Why am I required to reference System.Numerics with this simple LINQ expression?

首先,我知道如何reference System.Numerics让编译器访问它要求的Complex类型,我只是不明白为什么有必要。

我有这个基本结构:

/// <summary>
///     Describes a single point on a spectrum.
/// </summary>
public struct SpectrumPoint
{
    public SpectrumPoint(double wavelength, double intensity)
    {
        Wavelength = wavelength;
        Intensity = intensity;
    }
    public double Intensity { get; }
    public double Wavelength { get; }
}

它用在 class 中,需要 double[] 数组用作第三方依赖项的参数。我使用这个 LINQy lambda 链构造它们:

using Accord.Math;
// ...
double[] _wavelengths = points.Select(point => point.Wavelength).ToArray();
double[] _intensities = points.Select(point => point.Intensity).ToArray();

这是由那些 LINQ 表达式引起的错误:

Error CS0012
The type Complex is defined in an assembly that is not referenced.
You must add a reference to assembly
System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

我知道这种错误可能是由引用外部程序集的未使用方法重载引起的,例如 here,但 .Select().ToArray() 都没有引用 Complex 的重载。怎么回事?


编辑:

这完全复制了编译问题,如果删除 using Accord.Math;,该问题就会消失:

using System.Linq;
using Accord.Math;

public class A
{
    public A(IEnumerable<double> d)
    {
        double[] arr = d.ToArray();
    }
}

(HereAccord.Math。)

您可以查看 Github 上的 Accord.Math 项目,因为它引用了 System.Numerics。您很可能有一些代码使用引用 Complex 类型的 Accord.Math 类型,因此您需要引用 dll。

<ItemGroup> 
  <Reference Include="System" /> 
  <Reference Include="System.Data" /> 
  <Reference Include="System.Numerics" Condition="'$(Configuration)' != 'NET35'" /> 
  <Reference Include="System.Xml" /> 
</ItemGroup> 

我认为问题是由于 Accord.Math.ComplexMatrix - 带有一堆扩展方法的静态 class,包括:

public static double[,] ToArray(this Complex[] c);

我收到以下错误:

using static Accor.Math.ComplexMatrix;

...但是对于同一命名空间中的其他类型,我没有使用类似的 using static 指令来获得它。

将您的 ToArray 调用更改为显式 Enumerable.ToArray 调用可以消除错误:

_wavelengths = Enumerable.ToArray(points.Select(point => point.Wavelength));
_intensities = Enumerable.ToArray(points.Select(point => point.Intensity));

... 这进一步表明是 ComplexMatrix.ToArray 导致了问题。

基本上你不想使用任何导入的扩展方法。选项:

  • 如上图直接调用Enumerable.ToArray
  • 删除 using Accord.Math 并完全限定该命名空间中类型的任何使用
  • 使用名称空间别名,例如using AM = Accord.Math 然后将其用于命名空间中类型的任何用途,例如var p3 = new AM::Point3().
  • 为命名空间中需要的任何类型使用类型别名,例如using Point3 = Accord.Math.Point3; 那么你可以像往常一样使用 var p3 = new Point3();

现在诚然,编译器 可以 可能会计算出无论 Complex 是如何定义的,该调用都是不可行的,因为不可能有一个用户-定义了从 double[]Complex[] 的转换,但发现这会增加语言和编译器的复杂性。

这是一个真正简短但完整的示例来演示它:

using System.Linq;
using Accord.Math; // Comment this out and the error goes away

class Test
{
    static void Main(string[] args)
    {
        args.ToArray();
    }
}