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..?
CodePudding user response:
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);