Is there a constraint that restricts my generic method to numeric types?
Can anyone tell me if there is a way with generics to limit a generic type argument T
to only:
Int16
Int32
Int64
UInt16
UInt32
UInt64
I'm aware of the where
keyword, but can't find an interface for only these types,
Something like:
static bool IntegerFunction<T>(T value) where T : INumeric
Hejlsberg has described the reasons for not implementing the feature in an interview with Bruce Eckel.
I have to admit, though, that I don't know how he thinks his proposed workaround will work. His proposal is to defer arithmetic operations to some other generic class (read the interview!). How does this help? IMHO, not much.
Considering the popularity of this question and the interest behind such a function I am surprised to see that there is no answer involving T4 yet.
In this sample code I will demonstrate a very simple example of how you can use the powerful templating engine to do what the compiler pretty much does behind the scenes with generics.
Instead of going through hoops and sacrificing compile-time certainty you can simply generate the function you want for every type you like and use that accordingly (at compile time!).
In order to do this:
<#@ 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;
}
<#
} #>
}
That's it. You're done now.
Saving this file will automatically compile it to this source file:
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;
}
}
In your main
method you can verify that you have compile-time certainty:
namespace TTTTTest
{
class Program
{
static void Main(string[] args)
{
long val1 = 5L;
long val2 = 10L;
Console.WriteLine(MaxMath.Max(val1, val2));
Console.Read();
}
}
}
I'll get ahead of one remark: no, this is not a violation of the DRY principle. The DRY principle is there to prevent people from duplicating code in multiple places that would cause the application to become hard to maintain.
This is not at all the case here: if you want a change then you can just change the template (a single source for all your generation!) and it's done.
In order to use it with your own custom definitions, add a namespace declaration (make sure it's the same one as the one where you'll define your own implementation) to your generated code and mark the class as partial
. Afterwards, add these lines to your template file so it will be included in the eventual compilation:
<#@ import namespace="TheNameSpaceYouWillUse" #>
<#@ assembly name="$(TargetPath)" #>
Let's be honest: This is pretty cool.
Disclaimer: this sample has been heavily influenced by Metaprogramming in .NET by Kevin Hazzard and Jason Bock, Manning Publications.
There's no constraint for this. It's a real issue for anyone wanting to use generics for numeric calculations.
I'd go further and say we need
static bool GenericFunction<T>(T value)
where T : operators( +, -, /, * )
Or even
static bool GenericFunction<T>(T value)
where T : Add, Subtract
Unfortunately you only have interfaces, base classes and the keywords struct
(must be value-type), class
(must be reference type) and new()
(must have default constructor)
You could wrap the number in something else (similar to INullable<T>
) like here on codeproject.
You could apply the restriction at runtime (by reflecting for the operators or checking for types) but that does lose the advantage of having the generic in the first place.
链接地址: http://www.djcxy.com/p/33204.html上一篇: 哈斯克尔:哪里与让