如何在C#中模拟Java泛型通配符
How to simulate Java generic wildcards in C#
以下 Java 代码比较两个数组的平均值,一个整数数组和一个双精度数组。
class Generic_Class<T extends Number>
{
T[] nums; // array of Number or subclass
Generic_Class(T[] o)
{
nums = o;
}
// Return type double in all cases.
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
// boolean sameAvg(Generic_Class<T> ob)
// Using Generic_Class<T> i get the error:
// incompatible types: Generic_Class<Double> cannot be converted to Generic_Class<Integer>
// Using wilcards I get no error
boolean sameAvg(Generic_Class<?> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
主要方法是这样的:
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
Generic_Class<Integer> iob = new Generic_Class<Integer>(inums);
Generic_Class<Double> dob = new Generic_Class<Double>(dnums);
System.out.println("iob average is " + iob.average());
System.out.println("dob average is " + dob.average());
if (iob.sameAvg(dob))
System.out.println("Averages of iob and dob are the same.");
else
System.out.println("Averages of iob and dob differ.");
}
结果是:
iob average is 3.0
dob average is 3.0
Averages of iob and dob are the same.
我曾尝试在 C# 中执行相同的操作,但是由于没有通配符,我无法完成相同的任务。
如何使用 C# 执行相同的操作?
谢谢。
只需添加带有方法 double Average
的简单接口,这样您就可以:
interface IAbleToGetAverage
{
double Average();
}
class GenericClass<T> : IAbleToGetAverage
where T : struct, IConvertible
{
private readonly T[] nums; // array of Number or subclass
public GenericClass(T[] o)
{
nums = o;
}
private readonly IFormatProvider formatProvider = new NumberFormatInfo();
public double Average()
{
var sum = 0.0;
for(var i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(formatProvider);
return sum / nums.Length;
}
public bool SameAvg(IAbleToGetAverage ob)
{
if(Math.Abs(Average() - ob.Average()) < double.Epsilon)
return true;
return false;
}
}
您在 Java 代码中表达的是盒装数字类型,它们都扩展了 Number
class,因此强制执行泛型类型的约束是微不足道的一个号码。
类型在 C# 中的工作方式略有不同,因为 int
而不是与 Java 相同意义上的原始类型,只是 System.Int32
的类型别名,它是 struct
.
此外,在 C# 中没有仅由数字共享的公共基类型(class、结构、接口等),因此 不可能创建约束以强制泛型类型是数字,具有数值,因此可以对其执行数学计算。
这里的一些建议似乎是使用 where T : IComparable, struct
但我可以争辩说该约束也适用于 DateTime
、Guid
和 TimeSpan
- none 其中是整数或浮点数。
正如其他回答者所说,在 C# 中没有 Number
的等价物。你能得到的最好的是struct, IConvertible
。但是,还有另一种处理通用通配符的方法。
只需使用另一个通用参数:
public class Generic_Class<T> where T : struct, IConvertible
{
T[] nums;
public Generic_Class(T[] o)
{
nums = o;
}
public double Average()
{
double sum = 0.0;
for(int i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(null);
return sum / nums.Length;
}
// this is the important bit
public bool SameAvg<U>(Generic_Class<U> ob) where U : struct, IConvertible
{
if(Average() == ob.Average())
return true;
return false;
}
}
对数字序列取平均值 built-in 到 C#:
var iNums = new int[] { 1, 2, 3, 4, 5 };
var dNums = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 };
var iAvg = iNums.Average();
var dAvg = dNums.Average();
var areEqual = iAvg == dAvg;
areEqual == true
在 运行 以上之后。
您甚至可以使用带有 Func<TSource, T>
到 return 值的 Average
重载对复杂类型执行此操作:
public class MyValue
{
private static Random rnd = new Random();
public int SomeInt { get; set; } = rnd.Next();
}
var myObjArray = new MyValue[] { new MyValue(), new MyValue(), new MyValue(), new MyValue() };
var myAvg = myObjArray.Average(o => o.SomeInt);
所以不,通配符在 C# 中不可用,但在这种情况下,您可以使用泛型通过 Func
的多个重载来模拟通配符。
以下 Java 代码比较两个数组的平均值,一个整数数组和一个双精度数组。
class Generic_Class<T extends Number>
{
T[] nums; // array of Number or subclass
Generic_Class(T[] o)
{
nums = o;
}
// Return type double in all cases.
double average()
{
double sum = 0.0;
for(int i=0; i < nums.length; i++)
sum += nums[i].doubleValue();
return sum / nums.length;
}
// boolean sameAvg(Generic_Class<T> ob)
// Using Generic_Class<T> i get the error:
// incompatible types: Generic_Class<Double> cannot be converted to Generic_Class<Integer>
// Using wilcards I get no error
boolean sameAvg(Generic_Class<?> ob)
{
if(average() == ob.average())
return true;
return false;
}
}
主要方法是这样的:
public static void main(String args[])
{
Integer inums[] = { 1, 2, 3, 4, 5 };
Double dnums[] = { 1.0, 2.0, 3.0, 4.0, 5.0 };
Generic_Class<Integer> iob = new Generic_Class<Integer>(inums);
Generic_Class<Double> dob = new Generic_Class<Double>(dnums);
System.out.println("iob average is " + iob.average());
System.out.println("dob average is " + dob.average());
if (iob.sameAvg(dob))
System.out.println("Averages of iob and dob are the same.");
else
System.out.println("Averages of iob and dob differ.");
}
结果是:
iob average is 3.0
dob average is 3.0
Averages of iob and dob are the same.
我曾尝试在 C# 中执行相同的操作,但是由于没有通配符,我无法完成相同的任务。
如何使用 C# 执行相同的操作?
谢谢。
只需添加带有方法 double Average
的简单接口,这样您就可以:
interface IAbleToGetAverage
{
double Average();
}
class GenericClass<T> : IAbleToGetAverage
where T : struct, IConvertible
{
private readonly T[] nums; // array of Number or subclass
public GenericClass(T[] o)
{
nums = o;
}
private readonly IFormatProvider formatProvider = new NumberFormatInfo();
public double Average()
{
var sum = 0.0;
for(var i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(formatProvider);
return sum / nums.Length;
}
public bool SameAvg(IAbleToGetAverage ob)
{
if(Math.Abs(Average() - ob.Average()) < double.Epsilon)
return true;
return false;
}
}
您在 Java 代码中表达的是盒装数字类型,它们都扩展了 Number
class,因此强制执行泛型类型的约束是微不足道的一个号码。
类型在 C# 中的工作方式略有不同,因为 int
而不是与 Java 相同意义上的原始类型,只是 System.Int32
的类型别名,它是 struct
.
此外,在 C# 中没有仅由数字共享的公共基类型(class、结构、接口等),因此 不可能创建约束以强制泛型类型是数字,具有数值,因此可以对其执行数学计算。
这里的一些建议似乎是使用 where T : IComparable, struct
但我可以争辩说该约束也适用于 DateTime
、Guid
和 TimeSpan
- none 其中是整数或浮点数。
正如其他回答者所说,在 C# 中没有 Number
的等价物。你能得到的最好的是struct, IConvertible
。但是,还有另一种处理通用通配符的方法。
只需使用另一个通用参数:
public class Generic_Class<T> where T : struct, IConvertible
{
T[] nums;
public Generic_Class(T[] o)
{
nums = o;
}
public double Average()
{
double sum = 0.0;
for(int i=0; i < nums.Length; i++)
sum += nums[i].ToDouble(null);
return sum / nums.Length;
}
// this is the important bit
public bool SameAvg<U>(Generic_Class<U> ob) where U : struct, IConvertible
{
if(Average() == ob.Average())
return true;
return false;
}
}
对数字序列取平均值 built-in 到 C#:
var iNums = new int[] { 1, 2, 3, 4, 5 };
var dNums = new double[] { 1.0, 2.0, 3.0, 4.0, 5.0 };
var iAvg = iNums.Average();
var dAvg = dNums.Average();
var areEqual = iAvg == dAvg;
areEqual == true
在 运行 以上之后。
您甚至可以使用带有 Func<TSource, T>
到 return 值的 Average
重载对复杂类型执行此操作:
public class MyValue
{
private static Random rnd = new Random();
public int SomeInt { get; set; } = rnd.Next();
}
var myObjArray = new MyValue[] { new MyValue(), new MyValue(), new MyValue(), new MyValue() };
var myAvg = myObjArray.Average(o => o.SomeInt);
所以不,通配符在 C# 中不可用,但在这种情况下,您可以使用泛型通过 Func
的多个重载来模拟通配符。