简体   繁体   中英

Why Can't I implement generic method in C#?

I am trying to implement a simple generic method in c# that can convert from an NI ComplexSingle and NI ComplexDouble which are structs to a Complex as defined in System.Numerics , which is also a struct. Both ComplexSingle and ComplexDouble have properties Real and Imaginary defined here:

    public double Real
    {
        get
        {
            return _privateBackingFieldForProperty_Real;
        }
        set
        {
            double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
            _privateBackingFieldForProperty_Real = value;
        }
    }

    public double Imaginary
    {
        get
        {
            return _privateBackingFieldForProperty_Imaginary;
        }
        set
        {
            double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
            _privateBackingFieldForProperty_Imaginary = value;
        }
    }

All I want to do is make a single function that can take in either a ComplexSingle array or ComplexDouble array and convert either one into a Complex array. I was hoping to do that by using a generic method as below. However, I soon realized that the Real and Imaginary properties could not be found because the generic passed in doesn't know about them. Then, I thought maybe I could use an interface, which I defined below that has the properties that are found in the actual struct. Now I am getting an error below at:

Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);

that

在此处输入图像描述

Code is below:

using NationalInstruments;
using System;
using System.Numerics;

namespace ComplexStuff
{
    class ComplexMod
    {

        static void Main(string[] args)
        {
            Complex c1 = new Complex(4, 3);
            Complex c2 = new Complex(5, 4);
            Complex c3 = new Complex(6, 5);
            ComplexDouble cd1 = new ComplexDouble(4, 3);
            ComplexDouble cd2 = new ComplexDouble(4, 3);
            ComplexDouble cd3 = new ComplexDouble(4, 3);
            ComplexSingle cs1 = new ComplexSingle(7, 2);
            ComplexSingle cs2 = new ComplexSingle(7, 2);
            ComplexSingle cs3 = new ComplexSingle(7, 2);

            ComplexDouble[] cd = new ComplexDouble[]{
                cd1, cd2, cd3
            };
            Complex[] complexes = ComplexNItoComplex<ComplexDouble>(cd);


        }
        public interface IComplexNI
        {
            public double Real { get; set; }
            public double Imaginary { get; set; }
        }

        static Complex[] ComplexNItoComplex<T>(IList<T> NIComplex) where T : IComplexNI
        {
            Complex[] c = new Complex[NIComplex.Count];
            for (int i = 0; i < NIComplex.Count; i++)
            {
                c[i] = new Complex(NIComplex[i].Real, NIComplex[i].Imaginary);
            }
            return c;
        }
    }
}

Complex Double:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Runtime.Serialization;
using System.Security;
using NationalInstruments.Internal;
using NationalInstruments.Restricted;

namespace NationalInstruments
{
[Serializable]
[DebuggerDisplay("\\{{Real} + {Imaginary}i}")]
[TypeConverter(typeof(ComplexDoubleConverter))]
public struct ComplexDouble : IFormattable, ISerializable, IEquatable<ComplexDouble>
{
    private const string RealKey = "Real";

    private const string ImaginaryKey = "Imaginary";

    private double _privateBackingFieldForProperty_Real;

    private double _privateBackingFieldForProperty_Imaginary;

    public double Magnitude => Math.Sqrt(Real * Real + Imaginary * Imaginary);

    public double Phase => Math.Atan2(Imaginary, Real);

    public static ComplexDouble Zero => new ComplexDouble(0.0, 0.0);

    public ComplexDouble ComplexConjugate => new ComplexDouble(Real, 0.0 - Imaginary);

    public double Real
    {
        get
        {
            return _privateBackingFieldForProperty_Real;
        }
        set
        {
            double privateBackingFieldForProperty_Real = _privateBackingFieldForProperty_Real;
            _privateBackingFieldForProperty_Real = value;
        }
    }

    public double Imaginary
    {
        get
        {
            return _privateBackingFieldForProperty_Imaginary;
        }
        set
        {
            double privateBackingFieldForProperty_Imaginary = _privateBackingFieldForProperty_Imaginary;
            _privateBackingFieldForProperty_Imaginary = value;
        }
    }

    public ComplexDouble(double real, double imaginary)
    {
        this = default(ComplexDouble);
        Real = real;
        Imaginary = imaginary;
    }

    public static ComplexDouble FromPolar(double magnitude, double phase)
    {
        return new ComplexDouble(magnitude * Math.Cos(phase), magnitude * Math.Sin(phase));
    }

    public static ComplexDouble FromDouble(double real)
    {
        return new ComplexDouble(real, 0.0);
    }

    public static explicit operator ComplexDouble(double real)
    {
        return FromDouble(real);
    }

    public override string ToString()
    {
        return ToString(null, null);
    }

    public string ToString(string format)
    {
        return ToString(format, null);
    }

    public string ToString(IFormatProvider formatProvider)
    {
        return ToString(null, formatProvider);
    }

    public string ToString(string format, IFormatProvider formatProvider)
    {
        string text = Real.ToString(format, formatProvider);
        string text2 = Math.Abs(Imaginary).ToString(format, formatProvider);
        NumberFormatInfo numberFormat = ComplexParser.GetNumberFormat(formatProvider);
        string text3 = (Real.IsNegativeZero() ? numberFormat.NegativeSign : null);
        string text4 = ((Imaginary < 0.0 || Imaginary.IsNegativeZero()) ? numberFormat.NegativeSign : numberFormat.PositiveSign);
        return string.Format(CultureInfo.InvariantCulture, "{0}{1} {2} {3}i", text3, text, text4, text2);
    }

    public static ComplexDouble Parse(string input)
    {
        return Parse(input, null);
    }

    public static ComplexDouble Parse(string input, IFormatProvider provider)
    {
        if (input == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("input");
        }

        if (!ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out var real, out var imaginary))
        {
            throw ExceptionBuilder.InvalidComplexDoubleFormat(input);
        }

        return new ComplexDouble(real, imaginary);
    }

    public static bool TryParse(string input, out ComplexDouble result)
    {
        return TryParse(input, null, out result);
    }

    public static bool TryParse(string input, IFormatProvider provider, out ComplexDouble result)
    {
        double real;
        double imaginary;
        bool result2 = ComplexParser.AttemptParse(input, NumberStyles.Float | NumberStyles.AllowThousands, provider, ComplexParser.TryParseDouble, out real, out imaginary);
        result = new ComplexDouble(real, imaginary);
        return result2;
    }

    public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData)
    {
        if (realData == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("realData");
        }

        if (imaginaryData == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
        }

        int num = realData.Length;
        if (num != imaginaryData.Length)
        {
            throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
        }

        ComplexDouble[] array = new ComplexDouble[num];
        for (int i = 0; i < num; i++)
        {
            array[i] = new ComplexDouble(realData[i], imaginaryData[i]);
        }

        return array;
    }

    public static ComplexDouble[] ComposeArray(double[] realData, double[] imaginaryData, int startIndex, int length)
    {
        if (realData == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("realData");
        }

        if (imaginaryData == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("imaginaryData");
        }

        int num = realData.Length;
        if (num != imaginaryData.Length)
        {
            throw ExceptionBuilder.ArrayLengthsNotEqual("imaginaryData");
        }

        if (startIndex < realData.GetLowerBound(0) || startIndex >= num)
        {
            throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
        }

        if (length < 0 || startIndex + length > num)
        {
            throw ExceptionBuilderBase.ArgumentOutOfRange("length");
        }

        ComplexDouble[] array = new ComplexDouble[length];
        int num2 = startIndex;
        int num3 = 0;
        while (num2 < startIndex + length)
        {
            array[num3] = new ComplexDouble(realData[num2], imaginaryData[num2]);
            num2++;
            num3++;
        }

        return array;
    }

    public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases)
    {
        if (magnitudes == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("magnitudes");
        }

        if (phases == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("phases");
        }

        int num = magnitudes.Length;
        if (num != phases.Length)
        {
            throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
        }

        ComplexDouble[] array = new ComplexDouble[num];
        for (int i = 0; i < num; i++)
        {
            array[i] = FromPolar(magnitudes[i], phases[i]);
        }

        return array;
    }

    public static ComplexDouble[] ComposeArrayPolar(double[] magnitudes, double[] phases, int startIndex, int length)
    {
        if (magnitudes == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("magnitudes");
        }

        if (phases == null)
        {
            throw ExceptionBuilderBase.ArgumentNull("phases");
        }

        int num = magnitudes.Length;
        if (num != phases.Length)
        {
            throw ExceptionBuilder.ArrayLengthsNotEqual("phases");
        }

        if (startIndex < magnitudes.GetLowerBound(0) || startIndex >= num)
        {
            throw ExceptionBuilderBase.ArgumentOutOfRange("startIndex");
        }

        if (length < 0 || startIndex + length > num)
        {
            throw ExceptionBuilderBase.ArgumentOutOfRange("length");
        }
}

}

I know that the error only occurs if I have the real and imaginary properties in IComplexNI. I'm thinking I don't quite understand interfaces fully, since I was thinking that since I have Real and Complex defined in the interface, then the code would know to look for them when looking in the generic type. I guess that's wrong, though. I was guessing that you could reference the properties of objects or structs somehow in generic methods, but it sounds more complicated than what I was hoping..?

You can't write a single method to convert both types. Both types have a Real and an Imaginary property each, but the types of these properties are different.

The ComplexDouble type has Real and Imaginary properties of type double .

The ComplexSingle type has Real and Imaginary properties of type float .

The easiest solution is to use method overloading: You can have two methods with the same name and different parameter types. The compiler will then choose the correct method automatically based on the type of argument you pass to them:

static Complex[] ComplexNItoComplex(IEnumerable<ComplexDouble> NIComplex)
{
    return (from c in NIComplex
           select new Complex(c.Real, c.Imaginary))
           .ToArray();
}

static Complex[] ComplexNItoComplex(IEnumerable<ComplexSingle> NIComplex)
{
    return (from c in NIComplex
            select new Complex(c.Real, c.Imaginary))
           .ToArray();
}

Sample usage:

ComplexDouble cd1 = new ComplexDouble(4, 3);
ComplexDouble cd2 = new ComplexDouble(4, 3);
ComplexDouble cd3 = new ComplexDouble(4, 3);
ComplexSingle cs1 = new ComplexSingle(7, 2);
ComplexSingle cs2 = new ComplexSingle(7, 2);
ComplexSingle cs3 = new ComplexSingle(7, 2);

ComplexDouble[] cd = new ComplexDouble[]{
    cd1, cd2, cd3
};
ComplexSingle[] cs = new ComplexSingle[]{
    cs1, cs2, cs3
};

Complex[] complexes1 = ComplexNItoComplex(cd);
Complex[] complexes2 = ComplexNItoComplex(cs);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM