java限制数字_是否存在将我的通用方法限制为数字类型的约束?

谁能告诉我泛型是否可以将泛型类型参数T限制为:

Int16

Int32

Int64

UInt16

UInt32

UInt64

我知道where关键字,但是找不到仅适用于这些类型的接口,

就像是:

static bool IntegerFunction(T value) where T : INumeric

#1楼

这个问题有点像是一个常见问题,所以我将其发布为Wiki(因为我之前发布过类似的文章,但这是一个较旧的问题); 无论如何...

您正在使用什么版本的.NET? 如果您使用的是.NET 3.5,那么我在MiscUtil (免费等)中有一个通用的运算符实现 。

它具有T Add(T x, T y) ,以及用于不同类型(如DateTime + TimeSpan )的其他算术变体。

此外,这适用于所有内置,提升和定制的运算符,并缓存代表以提高性能。

为什么这是棘手的一些其他背景在这里 。

您可能还想知道dynamic (4.0)排序也间接解决了此问题-即

dynamic x = ..., y = ...

dynamic result = x + y; // does what you expect

#2楼

.NET数字基元类型不共享任何允许它们用于计算的通用接口。 可以定义自己的接口(例如ISignedWholeNumber ),该接口将执行此类操作,定义包含单个Int16 , Int32等的结构并实现这些接口,然后具有接受约束到ISignedWholeNumber泛型类型的方法,但具有将数值转换为您的结构类型可能会很麻烦。

一种替代方法是使用静态属性bool Available {get;};定义静态类Int64Converter bool Available {get;}; 以及Int64 GetInt64(T value) , T FromInt64(Int64 value) , bool TryStoreInt64(Int64 value, ref T dest)静态委托。 该类的构造函数可以使用硬编码来加载已知类型的委托,并可以使用Reflection来测试T类型是否使用正确的名称和签名来实现方法(如果它像包含Int64并表示数字的结构那样,但具有自定义的ToString()方法)。 这种方法将失去与编译时类型检查相关的优势,但是仍然可以避免装箱操作,并且每种类型仅需“检查”一次。 之后,与该类型关联的操作将被委托分派替换。

#3楼

我创建了一些库功能来解决这些问题:

代替:

public T DifficultCalculation(T a, T b)

{

T result = a * b + a; // <== WILL NOT COMPILE!

return result;

}

Console.WriteLine(DifficultCalculation(2, 3)); // Should result in 8.

您可以这样写:

public T DifficultCalculation(Number a, Number b)

{

Number result = a * b + a;

return (T)result;

}

Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8.

#4楼

我会使用一种通用的,您可以处理外部性...

///

/// Generic object copy of the same type

///

/// The type of object to copy

/// The source object to copy

public T CopyObject(T ObjectSource)

{

T NewObject = System.Activator.CreateInstance();

foreach (PropertyInfo p in ObjectSource.GetType().GetProperties())

NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null);

return NewObject;

}

#5楼

考虑到这个问题的普遍性以及这种功能背后的兴趣,我很惊讶地看到还没有涉及T4的答案。

在这个示例代码中,我将演示一个非常简单的示例,说明如何使用功能强大的模板引擎来完成编译器在泛型背后的工作。

您无需花钱,也不必牺牲编译时的确定性,您只需为所需的每种类型生成所需的函数,然后相应地使用它即可(在编译时!)。

为此:

创建一个名为GenericNumberMethodTemplate.tt的新文本模板文件。

删除自动生成的代码(您将保留其中的大部分,但不需要其中的一部分)。

添加以下代码段:

typeof(Int16), typeof(Int32), typeof(Int64),

typeof(UInt16), typeof(UInt32), typeof(UInt64)

};

#>

using System;

public static class MaxMath {

#>

public static Max ( val1, val2) {

return val1 > val2 ? val1 : val2;

}

} #>

}

而已。 现在完成了。

保存此文件将自动将其编译为该源文件:

using System;

public static class MaxMath {

public static Int16 Max (Int16 val1, Int16 val2) {

return val1 > val2 ? val1 : val2;

}

public static Int32 Max (Int32 val1, Int32 val2) {

return val1 > val2 ? val1 : val2;

}

public static Int64 Max (Int64 val1, Int64 val2) {

return val1 > val2 ? val1 : val2;

}

public static UInt16 Max (UInt16 val1, UInt16 val2) {

return val1 > val2 ? val1 : val2;

}

public static UInt32 Max (UInt32 val1, UInt32 val2) {

return val1 > val2 ? val1 : val2;

}

public static UInt64 Max (UInt64 val1, UInt64 val2) {

return val1 > val2 ? val1 : val2;

}

}

在您的main方法中,您可以验证自己具有编译时确定性:

namespace TTTTTest

{

class Program

{

static void Main(string[] args)

{

long val1 = 5L;

long val2 = 10L;

Console.WriteLine(MaxMath.Max(val1, val2));

Console.Read();

}

}

}

858c0582b9d085f2c1ada8971fda4d1a.png

我先说一句话​​:不,这不违反DRY原则。 DRY原则是为了防止人们在多个地方复制代码,这将导致应用程序变得难以维护。

这里根本不是这种情况:如果您想进行更改,则只需更改模板(您这一代人的一个单一来源!)就可以完成。

为了将其与您自己的自定义定义一起使用,请在生成的代码中添加一个名称空间声明(确保它与定义自己的实现的声明相同),并将该类标记为partial 。 然后,将这些行添加到模板文件中,以便将其包括在最终的编译中:

老实说:这很酷。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值