是否有一个限制,我的generics方法数值types?

任何人都可以告诉我,如果有generics的方法来限制genericstypes参数T只:

  • Int16
  • Int32
  • Int64
  • UInt16
  • UInt32
  • UInt64

我知道where关键字,但不能find只有这些types的接口,

就像是:

 static bool IntegerFunction<T>(T value) where T : INumeric 

Hejlsberg 在接受 Bruce Eckel 采访时描述了不实施该function的原因。

不过,我不得不承认,我不知道他如何认为他提出的解决方法是可行的。 他的提议是把算术运算推迟到其他一些通用类(阅读面试!)。 这有什么帮助? 恕我直言,不是很多。

这没有限制。 任何人想要使用generics进行数值计算都是一个真正的问题。

我会走得更远,说我们需要

 static bool GenericFunction<T>(T value) where T : operators( +, -, /, * ) 

甚至

 static bool GenericFunction<T>(T value) where T : Add, Subtract 

不幸的是,你只有接口,基类和关键字struct (必须是值types), class (必须是引用types)和new() (必须有默认的构造函数)

你可以把这个数字INullable<T>别的东西(类似于INullable<T> ),就像这里的codeproject一样 。


您可以在运行时应用限制(通过reflection操作符或检查types),但确实失去了将generics放在首位的好处。

考虑到这个问题的普及以及这样一个function背后的兴趣,我很惊讶地看到T4还没有答案。

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

你可以简单地生成你想要的每个types所需的函数,并相应地使用它(在编译时!),而不用花费大量时间和牺牲编译时的确定性。

为此:

  • 创build一个名为GenericNumberMethodTemplate.tt的新文本模板文件。
  • 删除自动生成的代码(您将保留大部分,但不需要)。
  • 添加下面的代码片段:
 <#@ template language="C#" #> <#@ output extension=".cs" #> <#@ assembly name="System.Core" #> <# Type[] types = new[] { typeof(Int16), typeof(Int32), typeof(Int64), typeof(UInt16), typeof(UInt32), typeof(UInt64) }; #> using System; public static class MaxMath { <# foreach (var type in types) { #> public static <#= type.Name #> Max (<#= type.Name #> val1, <#= type.Name #> 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方法中,你可以validation你有编译时的确定性:

 namespace TTTTTest { class Program { static void Main(string[] args) { long val1 = 5L; long val2 = 10L; Console.WriteLine(MaxMath.Max(val1, val2)); Console.Read(); } } } 

在这里输入图像描述

我会提前一条评论:不,这不违反DRY原则。 DRY原则是为了防止人们在多个地方复制代码,导致应用程序难以维护。

这里并不完全是这样的:如果你想要改变,那么你可以改变模板(为你所有的一代提供一个单一的源代码),然后就完成了。

为了在你自己定义的定义中使用它,添加一个名字空间声明(确保它和你定义你自己实现的那个声明是一样的),并把这个类标记为partial 。 之后,将这些行添加到您的模板文件中,以便将其包含在最终的编译中:

 <#@ import namespace="TheNameSpaceYouWillUse" #> <#@ assembly name="$(TargetPath)" #> 

说实话:这很酷。

免责声明:这个样本受到了由Manning出版公司的Kevin Hazzard和Jason Bock在.NET中的Metaprogramming的严重影响。

使用策略的解决方法:

 interface INumericPolicy<T> { T Zero(); T Add(T a, T b); // add more functions here, such as multiplication etc. } struct NumericPolicies: INumericPolicy<int>, INumericPolicy<long> // add more INumericPolicy<> for different numeric types. { int INumericPolicy<int>.Zero() { return 0; } long INumericPolicy<long>.Zero() { return 0; } int INumericPolicy<int>.Add(int a, int b) { return a + b; } long INumericPolicy<long>.Add(long a, long b) { return a + b; } // implement all functions from INumericPolicy<> interfaces. public static NumericPolicies Instance = new NumericPolicies(); } 

algorithm:

 static class Algorithms { public static T Sum<P, T>(this P p, params T[] a) where P: INumericPolicy<T> { var r = p.Zero(); foreach(var i in a) { r = p.Add(r, i); } return r; } } 

用法:

 int i = NumericPolicies.Instance.Sum(1, 2, 3, 4, 5); long l = NumericPolicies.Instance.Sum(1L, 2, 3, 4, 5); NumericPolicies.Instance.Sum("www", "") // compile-time error. 

更新:解决scheme是编译时安全的。 CityLizard框架提供了.NET 4.0的编译版本。 该文件是lib / NETFramework4.0 / CityLizard.Policy.dll。

更新2:代码已更新,因此可以编译。

更新3:在Nuget中: https //www.nuget.org/packages/CityLizard/ 请参阅CityLizard.Policy.I结构。

更新4:将“All.P”重命名为“NumericPolicies.Instance”。

不幸的是,你只能在这个实例的where子句中指定struct。 看起来很奇怪,你不能指定Int16,Int32等,但是我确定有一些深层次的实现原因决定了不允许where子句中的值types。

我想唯一的解决办法是做一个运行时检查,不幸的是防止在编译时拾取问题。 那会像这样:

 static bool IntegerFunction<T>(T value) where T : struct { if (typeof(T) != typeof(Int16) && typeof(T) != typeof(Int32) && typeof(T) != typeof(Int64) && typeof(T) != typeof(UInt16) && typeof(T) != typeof(UInt32) && typeof(T) != typeof(UInt64)) { throw new ArgumentException( string.Format("Type '{0}' is not valid.", typeof(T).ToString())); } // Rest of code... } 

我知道这有点难看,但至less提供了必要的约束条件。

我也会研究这个实现可能的性能影响,也许有更快的方法。

这个问题是一个常见问题,所以我发布这个wiki(因为我以前发布类似,但这是一个较旧的); 无论如何…

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

这有像T Add<T>(T x, T y)和其他变体在不同types(如DateTime + TimeSpan )上的算术。

此外,这适用于所有内置,解除和定制的操作员,并caching代表的performance。

为什么这是棘手的一些额外的背景是在这里 。

你也可能想知道, dynamic (4.0)sorting也间接解决了这个问题 – 即

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

可能最接近你能做的是

 static bool IntegerFunction<T>(T value) where T: struct 

不知道你是否可以做到以下几点

 static bool IntegerFunction<T>(T value) where T: struct, IComparable , IFormattable, IConvertible, IComparable<T>, IEquatable<T> 

对于如此特定的内容,为什么不为每种types重载,列表太短,可能会占用更less的内存。

没有办法将模板限制为types,但可以根据types定义不同的操作。 作为通用数字包的一部分,我需要一个generics类来添加两个值。

  class Something<TCell> { internal static TCell Sum(TCell first, TCell second) { if (typeof(TCell) == typeof(int)) return (TCell)((object)(((int)((object)first)) + ((int)((object)second)))); if (typeof(TCell) == typeof(double)) return (TCell)((object)(((double)((object)first)) + ((double)((object)second)))); return second; } } 

请注意,typeofs是在编译时计算的,所以if语句将被编译器删除。 编译器还会删除虚假的强制转换。 所以有些东西会在编译器中解决

  internal static int Sum(int first, int second) { return first + second; } 

我想知道萨米德森一样,为什么只有整数? 如果是这样的话,你可能想创build一个辅助类或类似的东西来保存所有你想要的types。

如果你想要的只是整数,那么不要使用generics的generics。 或者更好,通过检查其types来拒绝任何其他types。

我创build了一个小库函数来解决这些问题:

代替:

 public T DifficultCalculation<T>(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<T>(Number<T> a, Number<T> b) { Number<T> result = a * b + a; return (T)result; } Console.WriteLine(DifficultCalculation(2, 3)); // Results in 8. 

你可以在这里find源代码: https : //codereview.stackexchange.com/questions/26022/improvement-requested-for-generic-calculator-and-generic-number

练习的要点是什么?

正如人们已经指出的那样,您可以拥有一个非generics函数来获取最大的项目,编译器会自动为您转换更小的值。

 static bool IntegerFunction(Int64 value) { } 

如果你的函数在性能关键path上(不太可能,IMO),你可以提供所有需要的函数的重载。

 static bool IntegerFunction(Int64 value) { } ... static bool IntegerFunction(Int16 value) { } 

我会使用一个通用的,你可以处理externaly …

 /// <summary> /// Generic object copy of the same type /// </summary> /// <typeparam name="T">The type of object to copy</typeparam> /// <param name="ObjectSource">The source object to copy</param> public T CopyObject<T>(T ObjectSource) { T NewObject = System.Activator.CreateInstance<T>(); foreach (PropertyInfo p in ObjectSource.GetType().GetProperties()) NewObject.GetType().GetProperty(p.Name).SetValue(NewObject, p.GetValue(ObjectSource, null), null); return NewObject; } 

当我试图为genericstypes重载运算符时,这个限制影响了我; 由于没有“INumeric”约束,并且由于其他原因,在stackoverflow上的好人很乐意提供,操作无法在generics上定义。

我想要类似的东西

 public struct Foo<T> { public T Value{ get; private set; } public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS) { return new Foo<T> { Value = LHS.Value + RHS.Value; }; } } 

我已经使用.net4dynamic运行时键入解决了这个问题。

 public struct Foo<T> { public T Value { get; private set; } public static Foo<T> operator +(Foo<T> LHS, Foo<T> RHS) { return new Foo<T> { Value = LHS.Value + (dynamic)RHS.Value }; } } 

关于使用dynamic的两件事是

  1. 性能。 所有值types都被装箱。
  2. 运行时错误。 你“击败”编译器,但是失去了types安全性。 如果generics没有定义操作符,则在执行过程中会抛出exception。

这还没有“好”的解决scheme。 然而,你可以显着的缩小这个types的参数,从而排除你的假设的“INumeric”约束的许多不适应,正如Haacked上面所示。

静态布尔IntegerFunction <T>(T值)其中T:IComparable,IFormattable,IConvertible,IComparable <T>,IEquatable <T>,结构{…

.NET数字基元types不共享任何允许它们用于计算的通用接口。 有可能定义你自己的接口(例如ISignedWholeNumber )来执行这样的操作,定义包含单个Int16Int32等的结构,并实现这些接口,然后具有接受通用types的约束到ISignedWholeNumber ,将数值转换为您的结构types可能是一个麻烦。

另一种方法是使用静态属性bool Available {get;};来定义静态类Int64Converter<T> bool Available {get;};Int64 GetInt64(T value)T FromInt64(Int64 value)bool TryStoreInt64(Int64 value, ref T dest)静态委托。 类构造函数可以使用硬编码来加载已知types的委托,也可以使用Reflection来testingtypesT是否实现了具有正确名称和特征的方法(如果它类似于包含Int64的结构并表示一个数字,但有一个自定义的ToString()方法)。 这种方法将失去与编译时types检查相关的优点,但仍然可以避免装箱操作,并且每个types只需要“检查”一次。 之后,与该types相关的操作将被replace为委托调度。

如果您使用的是.NET 4.0及更高版本,则可以使用dynamic作为方法参数,并在运行时检查传递的dynamic参数types是数字/整数types。

如果传入的dynamictypes不是数字/整型,则抛出exception。

实现该想法的示例代码如下所示:

 using System; public class InvalidArgumentException : Exception { public InvalidArgumentException(string message) : base(message) {} } public class InvalidArgumentTypeException : InvalidArgumentException { public InvalidArgumentTypeException(string message) : base(message) {} } public class ArgumentTypeNotIntegerException : InvalidArgumentTypeException { public ArgumentTypeNotIntegerException(string message) : base(message) {} } public static class Program { private static bool IntegerFunction(dynamic n) { if (n.GetType() != typeof(Int16) && n.GetType() != typeof(Int32) && n.GetType() != typeof(Int64) && n.GetType() != typeof(UInt16) && n.GetType() != typeof(UInt32) && n.GetType() != typeof(UInt64)) throw new ArgumentTypeNotIntegerException("argument type is not integer type"); //code that implements IntegerFunction goes here } private static void Main() { Console.WriteLine("{0}",IntegerFunction(0)); //Compiles, no run time error and first line of output buffer is either "True" or "False" depends on the code that implements "Program.IntegerFunction" static method. Console.WriteLine("{0}",IntegerFunction("string")); //Also compiles but it is run time error and exception of type "ArgumentTypeNotIntegerException" is thrown here. Console.WriteLine("This is the last Console.WriteLine output"); //Never reached and executed due the run time error and the exception thrown on the second line of Program.Main static method. } 

当然,这个解决scheme只能在运行时间内运行,但从不在编译时间内。

如果你想要一个总是在编译时工作的解决scheme,而不是在运行时,那么你将不得不用dynamic的公共结构/类重载公共构造函数只接受所需types的参数,并给结构/类适当的名称。

这是有道理的,包装的dynamic永远是类/结构的私有成员,它是结构/类的唯一成员,结构/类的唯一成员的名称是“值”。

您还必须定义和实现公共方法和/或运算符(如果需要的话),使用类/结构的私有dynamic成员的所需types。

这也是有道理的,结构/类具有特殊/唯一的构造函数接受dynamic作为参数初始化它只有私人dynamic成员称为“价值”,但修饰符的这个构造是当然私人

一旦类/结构准备就绪,将参数的IntegerFunctiontypes定义为已定义的类/结构。

一个实现这个想法的例子代码如下所示:

 using System; public struct Integer { private dynamic value; private Integer(dynamic n) { this.value = n; } public Integer(Int16 n) { this.value = n; } public Integer(Int32 n) { this.value = n; } public Integer(Int64 n) { this.value = n; } public Integer(UInt16 n) { this.value = n; } public Integer(UInt32 n) { this.value = n; } public Integer(UInt64 n) { this.value = n; } public Integer(Integer n) { this.value = n.value; } public static implicit operator Int16(Integer n) { return n.value; } public static implicit operator Int32(Integer n) { return n.value; } public static implicit operator Int64(Integer n) { return n.value; } public static implicit operator UInt16(Integer n) { return n.value; } public static implicit operator UInt32(Integer n) { return n.value; } public static implicit operator UInt64(Integer n) { return n.value; } public static Integer operator +(Integer x, Int16 y) { return new Integer(x.value + y); } public static Integer operator +(Integer x, Int32 y) { return new Integer(x.value + y); } public static Integer operator +(Integer x, Int64 y) { return new Integer(x.value + y); } public static Integer operator +(Integer x, UInt16 y) { return new Integer(x.value + y); } public static Integer operator +(Integer x, UInt32 y) { return new Integer(x.value + y); } public static Integer operator +(Integer x, UInt64 y) { return new Integer(x.value + y); } public static Integer operator -(Integer x, Int16 y) { return new Integer(x.value - y); } public static Integer operator -(Integer x, Int32 y) { return new Integer(x.value - y); } public static Integer operator -(Integer x, Int64 y) { return new Integer(x.value - y); } public static Integer operator -(Integer x, UInt16 y) { return new Integer(x.value - y); } public static Integer operator -(Integer x, UInt32 y) { return new Integer(x.value - y); } public static Integer operator -(Integer x, UInt64 y) { return new Integer(x.value - y); } public static Integer operator *(Integer x, Int16 y) { return new Integer(x.value * y); } public static Integer operator *(Integer x, Int32 y) { return new Integer(x.value * y); } public static Integer operator *(Integer x, Int64 y) { return new Integer(x.value * y); } public static Integer operator *(Integer x, UInt16 y) { return new Integer(x.value * y); } public static Integer operator *(Integer x, UInt32 y) { return new Integer(x.value * y); } public static Integer operator *(Integer x, UInt64 y) { return new Integer(x.value * y); } public static Integer operator /(Integer x, Int16 y) { return new Integer(x.value / y); } public static Integer operator /(Integer x, Int32 y) { return new Integer(x.value / y); } public static Integer operator /(Integer x, Int64 y) { return new Integer(x.value / y); } public static Integer operator /(Integer x, UInt16 y) { return new Integer(x.value / y); } public static Integer operator /(Integer x, UInt32 y) { return new Integer(x.value / y); } public static Integer operator /(Integer x, UInt64 y) { return new Integer(x.value / y); } public static Integer operator %(Integer x, Int16 y) { return new Integer(x.value % y); } public static Integer operator %(Integer x, Int32 y) { return new Integer(x.value % y); } public static Integer operator %(Integer x, Int64 y) { return new Integer(x.value % y); } public static Integer operator %(Integer x, UInt16 y) { return new Integer(x.value % y); } public static Integer operator %(Integer x, UInt32 y) { return new Integer(x.value % y); } public static Integer operator %(Integer x, UInt64 y) { return new Integer(x.value % y); } public static Integer operator +(Integer x, Integer y) { return new Integer(x.value + y.value); } public static Integer operator -(Integer x, Integer y) { return new Integer(x.value - y.value); } public static Integer operator *(Integer x, Integer y) { return new Integer(x.value * y.value); } public static Integer operator /(Integer x, Integer y) { return new Integer(x.value / y.value); } public static Integer operator %(Integer x, Integer y) { return new Integer(x.value % y.value); } public static bool operator ==(Integer x, Int16 y) { return x.value == y; } public static bool operator !=(Integer x, Int16 y) { return x.value != y; } public static bool operator ==(Integer x, Int32 y) { return x.value == y; } public static bool operator !=(Integer x, Int32 y) { return x.value != y; } public static bool operator ==(Integer x, Int64 y) { return x.value == y; } public static bool operator !=(Integer x, Int64 y) { return x.value != y; } public static bool operator ==(Integer x, UInt16 y) { return x.value == y; } public static bool operator !=(Integer x, UInt16 y) { return x.value != y; } public static bool operator ==(Integer x, UInt32 y) { return x.value == y; } public static bool operator !=(Integer x, UInt32 y) { return x.value != y; } public static bool operator ==(Integer x, UInt64 y) { return x.value == y; } public static bool operator !=(Integer x, UInt64 y) { return x.value != y; } public static bool operator ==(Integer x, Integer y) { return x.value == y.value; } public static bool operator !=(Integer x, Integer y) { return x.value != y.value; } public override bool Equals(object obj) { return this == (Integer)obj; } public override int GetHashCode() { return this.value.GetHashCode(); } public override string ToString() { return this.value.ToString(); } public static bool operator >(Integer x, Int16 y) { return x.value > y; } public static bool operator <(Integer x, Int16 y) { return x.value < y; } public static bool operator >(Integer x, Int32 y) { return x.value > y; } public static bool operator <(Integer x, Int32 y) { return x.value < y; } public static bool operator >(Integer x, Int64 y) { return x.value > y; } public static bool operator <(Integer x, Int64 y) { return x.value < y; } public static bool operator >(Integer x, UInt16 y) { return x.value > y; } public static bool operator <(Integer x, UInt16 y) { return x.value < y; } public static bool operator >(Integer x, UInt32 y) { return x.value > y; } public static bool operator <(Integer x, UInt32 y) { return x.value < y; } public static bool operator >(Integer x, UInt64 y) { return x.value > y; } public static bool operator <(Integer x, UInt64 y) { return x.value < y; } public static bool operator >(Integer x, Integer y) { return x.value > y.value; } public static bool operator <(Integer x, Integer y) { return x.value < y.value; } public static bool operator >=(Integer x, Int16 y) { return x.value >= y; } public static bool operator <=(Integer x, Int16 y) { return x.value <= y; } public static bool operator >=(Integer x, Int32 y) { return x.value >= y; } public static bool operator <=(Integer x, Int32 y) { return x.value <= y; } public static bool operator >=(Integer x, Int64 y) { return x.value >= y; } public static bool operator <=(Integer x, Int64 y) { return x.value <= y; } public static bool operator >=(Integer x, UInt16 y) { return x.value >= y; } public static bool operator <=(Integer x, UInt16 y) { return x.value <= y; } public static bool operator >=(Integer x, UInt32 y) { return x.value >= y; } public static bool operator <=(Integer x, UInt32 y) { return x.value <= y; } public static bool operator >=(Integer x, UInt64 y) { return x.value >= y; } public static bool operator <=(Integer x, UInt64 y) { return x.value <= y; } public static bool operator >=(Integer x, Integer y) { return x.value >= y.value; } public static bool operator <=(Integer x, Integer y) { return x.value <= y.value; } public static Integer operator +(Int16 x, Integer y) { return new Integer(x + y.value); } public static Integer operator +(Int32 x, Integer y) { return new Integer(x + y.value); } public static Integer operator +(Int64 x, Integer y) { return new Integer(x + y.value); } public static Integer operator +(UInt16 x, Integer y) { return new Integer(x + y.value); } public static Integer operator +(UInt32 x, Integer y) { return new Integer(x + y.value); } public static Integer operator +(UInt64 x, Integer y) { return new Integer(x + y.value); } public static Integer operator -(Int16 x, Integer y) { return new Integer(x - y.value); } public static Integer operator -(Int32 x, Integer y) { return new Integer(x - y.value); } public static Integer operator -(Int64 x, Integer y) { return new Integer(x - y.value); } public static Integer operator -(UInt16 x, Integer y) { return new Integer(x - y.value); } public static Integer operator -(UInt32 x, Integer y) { return new Integer(x - y.value); } public static Integer operator -(UInt64 x, Integer y) { return new Integer(x - y.value); } public static Integer operator *(Int16 x, Integer y) { return new Integer(x * y.value); } public static Integer operator *(Int32 x, Integer y) { return new Integer(x * y.value); } public static Integer operator *(Int64 x, Integer y) { return new Integer(x * y.value); } public static Integer operator *(UInt16 x, Integer y) { return new Integer(x * y.value); } public static Integer operator *(UInt32 x, Integer y) { return new Integer(x * y.value); } public static Integer operator *(UInt64 x, Integer y) { return new Integer(x * y.value); } public static Integer operator /(Int16 x, Integer y) { return new Integer(x / y.value); } public static Integer operator /(Int32 x, Integer y) { return new Integer(x / y.value); } public static Integer operator /(Int64 x, Integer y) { return new Integer(x / y.value); } public static Integer operator /(UInt16 x, Integer y) { return new Integer(x / y.value); } public static Integer operator /(UInt32 x, Integer y) { return new Integer(x / y.value); } public static Integer operator /(UInt64 x, Integer y) { return new Integer(x / y.value); } public static Integer operator %(Int16 x, Integer y) { return new Integer(x % y.value); } public static Integer operator %(Int32 x, Integer y) { return new Integer(x % y.value); } public static Integer operator %(Int64 x, Integer y) { return new Integer(x % y.value); } public static Integer operator %(UInt16 x, Integer y) { return new Integer(x % y.value); } public static Integer operator %(UInt32 x, Integer y) { return new Integer(x % y.value); } public static Integer operator %(UInt64 x, Integer y) { return new Integer(x % y.value); } public static bool operator ==(Int16 x, Integer y) { return x == y.value; } public static bool operator !=(Int16 x, Integer y) { return x != y.value; } public static bool operator ==(Int32 x, Integer y) { return x == y.value; } public static bool operator !=(Int32 x, Integer y) { return x != y.value; } public static bool operator ==(Int64 x, Integer y) { return x == y.value; } public static bool operator !=(Int64 x, Integer y) { return x != y.value; } public static bool operator ==(UInt16 x, Integer y) { return x == y.value; } public static bool operator !=(UInt16 x, Integer y) { return x != y.value; } public static bool operator ==(UInt32 x, Integer y) { return x == y.value; } public static bool operator !=(UInt32 x, Integer y) { return x != y.value; } public static bool operator ==(UInt64 x, Integer y) { return x == y.value; } public static bool operator !=(UInt64 x, Integer y) { return x != y.value; } public static bool operator >(Int16 x, Integer y) { return x > y.value; } public static bool operator <(Int16 x, Integer y) { return x < y.value; } public static bool operator >(Int32 x, Integer y) { return x > y.value; } public static bool operator <(Int32 x, Integer y) { return x < y.value; } public static bool operator >(Int64 x, Integer y) { return x > y.value; } public static bool operator <(Int64 x, Integer y) { return x < y.value; } public static bool operator >(UInt16 x, Integer y) { return x > y.value; } public static bool operator <(UInt16 x, Integer y) { return x < y.value; } public static bool operator >(UInt32 x, Integer y) { return x > y.value; } public static bool operator <(UInt32 x, Integer y) { return x < y.value; } public static bool operator >(UInt64 x, Integer y) { return x > y.value; } public static bool operator <(UInt64 x, Integer y) { return x < y.value; } public static bool operator >=(Int16 x, Integer y) { return x >= y.value; } public static bool operator <=(Int16 x, Integer y) { return x <= y.value; } public static bool operator >=(Int32 x, Integer y) { return x >= y.value; } public static bool operator <=(Int32 x, Integer y) { return x <= y.value; } public static bool operator >=(Int64 x, Integer y) { return x >= y.value; } public static bool operator <=(Int64 x, Integer y) { return x <= y.value; } public static bool operator >=(UInt16 x, Integer y) { return x >= y.value; } public static bool operator <=(UInt16 x, Integer y) { return x <= y.value; } public static bool operator >=(UInt32 x, Integer y) { return x >= y.value; } public static bool operator <=(UInt32 x, Integer y) { return x <= y.value; } public static bool operator >=(UInt64 x, Integer y) { return x >= y.value; } public static bool operator <=(UInt64 x, Integer y) { return x <= y.value; } } public static class Program { private static bool IntegerFunction(Integer n) { //code that implements IntegerFunction goes here //note that there is NO code that checks the type of n in rum time, because it is NOT needed anymore } private static void Main() { Console.WriteLine("{0}",IntegerFunction(0)); //compile error: there is no overloaded METHOD for objects of type "int" and no implicit conversion from any object, including "int", to "Integer" is known. Console.WriteLine("{0}",IntegerFunction(new Integer(0))); //both compiles and no run time error Console.WriteLine("{0}",IntegerFunction("string")); //compile error: there is no overloaded METHOD for objects of type "string" and no implicit conversion from any object, including "string", to "Integer" is known. Console.WriteLine("{0}",IntegerFunction(new Integer("string"))); //compile error: there is no overloaded CONSTRUCTOR for objects of type "string" } } 

Note that in order to use dynamic in your code you must Add Reference to Microsoft.CSharp

If the version of the .NET framework is below/under/lesser than 4.0 and dynamic is undefined in that version then you will have to use object instead and do casting to the integer type, which is trouble, so I recommend that you use at least .NET 4.0 or newer if you can so you can use dynamic instead of object .

There is no single interface or base class that they all inherit (that is not also inherited by other classes) so the simple answer is no.

I do wonder why this is an issue though. What are you wanting to do inside your IntegerFunction class that can only be done to integers?

I think you are misunderstanding generics. If the operation you are trying to perform is only good for specific data types then you are not doing something "generic".

Also, since you are only wanting to allow the function to work on int data types then you shouldn't need a separate function for each specific size. Simply taking a parameter in the largest specific type will allow the program to automatically upcast the smaller data types to it. (ie passing an Int16 will auto-convert to Int64 when calling).

If you are performing different operations based on the actual size of int being passed into the function then I would think you should seriously reconsider even trying to do what you are doing. If you have to fool the language you should think a bit more about what you are trying to accomplish rather than how to do what you want.

Failing all else, a parameter of type Object could be used and then you will have to check the type of the parameter and take appropriate action or throw an exception.