Is there a constraint that restricts my generic method to numeric types?
C# does not support this. Hejlsberg has described the reasons for not implementing the feature in an interview with Bruce Eckel:
And it's not clear that the added complexity is worth the small yield that you get. If something you want to do is not directly supported in the constraint system, you can do it with a factory pattern. You could have a
Matrix<T>
, for example, and in thatMatrix
you would like to define a dot product method. That of course that means you ultimately need to understand how to multiply twoT
s, but you can't say that as a constraint, at least not ifT
isint
,double
, orfloat
. But what you could do is have yourMatrix
take as an argument aCalculator<T>
, and inCalculator<T>
, have a method calledmultiply
. You go implement that and you pass it to theMatrix
.
However, this leads to fairly convoluted code, where the user has to supply their own Calculator<T>
implementation, for each T
that they want to use. As long as it doesn’t have to be extensible, i.e. if you just want to support a fixed number of types, such as int
and double
, you can get away with a relatively simple interface:
var mat = new Matrix<int>(w, h);
(Minimal implementation in a GitHub Gist.)
However, as soon as you want the user to be able to supply their own, custom types, you need to open up this implementation so that the user can supply their own Calculator
instances. For instance, to instantiate a matrix that uses a custom decimal floating point implementation, DFP
, you’d have to write this code:
var mat = new Matrix<DFP>(DfpCalculator.Instance, w, h);
… and implement all the members for DfpCalculator : ICalculator<DFP>
.
An alternative, which unfortunately shares the same limitations, is to work with policy classes, as discussed in Sergey Shandar’s answer.
Generic constraint to match numeric types
In this case you want to constrain your generic to the IComparable
interface, which gives you access to the CompareTo
method, since this interface allows you to answer the question ShouldBeGreaterThan
.
Numeric types will implement that interface and the fact that it also works on strings shouldn't bother you that much.
Generics that restricts the types to Int, Double, long
This is not possible currently.
Also, see this question for a possible workaround
C# generic method with integer constraint refuses to cast from integer to the generic type
"Only class or interface could be specified as constraint." (c) ReSharper
int (Int32) is just a struct. You can constrain that T is a struct. but you can't use any struct as constraint.
the whole list of possible constraints you can find here - http://msdn.microsoft.com/en-us/library/d5x73970.aspx
UPD
and for Enum constraint see this question - Is there a workaround for generic type constraint of "special class" Enum in C# 3.0?
Restrict generic T to specific types
You can't restrict generics in that way, you can only choose a single class as a constraint. You must either make 5 overloads or find a interface all 5 of those things share and use that. Which option you choose will depend on what Validate
doe.
Here is how you would do the overloads.
public static IResult<Int16, String> Validate<T>(this Int16 value) {
} // Validate
public static IResult<Int32, String> Validate<T>(this Int32 value) {
} // Validate
public static IResult<Int64, String> Validate<T>(this Int64 value) {
} // Validate
public static IResult<double, String> Validate<T>(this double value) {
} // Validate
public static IResult<String, String> Validate<T>(this String value) {
} // Validate
Here is by using a common interface, all of the members you list Implement IConvertible
so you could restrict by that, however this will allow any IConvertible not just the 5 you listed.
public static IResult<T, String> Validate<T>(this T value) where IConvertible {
} // Validate
Limit a generic type argument only to be a numeric type
No, there is still no generic type constraint for a "numeric" type.
To get your T a = 0
specifically you can just use T a = default(T)
. The default of all numeric types is 0.
How to restrict T to value types using a constraint?
Unfortunately, it is not possible to specify generic type constraints that only allow specific value types. More to the point, it wouldn't make much sense even if it was allowed.
You're allowed to specify a class as a generic constraint but this is because you can inherit from classes, the constraint thus sets the minimum threshold of what types you're allowed to use.
If this was allowed for value types, where you cannot inherit from those types, you would effectively limit yourself to only that type.
Thus you cannot do this, but you have a few alternatives:
- You can declare it without the constraint, and handle the problem at runtime. I would not recommend this way
You can declare overloads that take the specific types you're interested in.
Since you only have two such types this is what I would recommend doing.
Here are the overloads you would declare:
public static Chart PopulateInto<T>(List<T> yAxis, List<int> xAxis)
{
// Do stuff here
}
public static Chart PopulateInto<T>(List<T> yAxis, List<decimal> xAxis)
{
// Do stuff here
}
Now, additionally, if your handling of those values doesn't really rely on the numeric quality of those types, you just want to limit which types you can handle, then you can always declare your original method as well, privately, and call this method from your overloads. This would still limit your code to only allowing int
or decimal
, publicly, but your implementation would still be generic. Without knowing exactly what "Do stuff here" entails it is impossible to tell if this is a viable option or not but here is the code anyway:
public static Chart PopulateInto<T>(List<T> yAxis, List<int> xAxis)
{
return PopulateInto<T, int>(yAxis, xAxis);
}
public static Chart PopulateInto<T>(List<T> yAxis, List<decimal> xAxis)
{
return PopulateInto<T, decimal>(yAxis, xAxis);
}
private static Chart PopulateInto<T, N>(List<T> yAxis, List<N> xAxis) where N : struct
{
// Do stuff here
}
Generic type constraint for numerical type only
You can specify type constraints (using both classes and protocols) for a generic class (same syntax applies to functions) using angle brackets:
class Foo<T: Equatable, U: Comparable> { }
To specify more than one requirement on a single type, use a where
clause:
class Foo<T: UIViewController where T: UITableViewDataSource, T: UITextFieldDelegate> { }
However, it doesn't look like you can specify optional requirements in a generic parameter clause, so one possible solution is to create a protocol that all the numeric types implement via extensions and then constrain your class on that requirement:
protocol Numeric { }
extension Float: Numeric {}
extension Double: Numeric {}
extension Int: Numeric {}
class NumberCruncher<C1: Numeric> {
func echo(num: C1)-> C1 {
return num
}
}
NumberCruncher<Int>().echo(42)
NumberCruncher<Float>().echo(3.14)
Is there a C# generic constraint for real number types?
You can't define such a constraint, but you could check the type at runtime. That won't help you for doing calculations though.
If you want to do calculations, something like this would be an option:
class Calculations<T, S> where S: Calculator<T>, new()
{
Calculator<T> _calculator = new S();
public T Square(T a)
{
return _calculator.Multiply(a, a);
}
}
abstract class Calculator<T>
{
public abstract T Multiply(T a, T b);
}
class IntCalculator : Calculator<int>
{
public override int Multiply(int a, int b)
{
return a * b;
}
}
Likewise, define a FloatCalculator
and any operations you need. It's not particularly fast, though faster than the C# 4.0 dynamic
construct.
var calc = new Calculations<int, IntCalculator>();
var result = calc.Square(10);
A side-effect is that you will only be able to instantiate Calculator
if the type you pass to it has a matching Calculator<T>
implementation, so you don't have to do runtime type checking.
This is basically what Hejlsberg was referring to in this interview where the issue is discussed. Personally I would still like to see some kind of base type :)
Related Topics
Does Page Reload Ever Cause Post
Send Http Post Request in .Net
The Calling Thread Cannot Access This Object Because a Different Thread Owns It
Is Using Random and Orderby a Good Shuffle Algorithm
One Dbcontext Per Web Request... Why
Asp.Net MVC 5 Culture in Route and Url
Mvc5 Razor Html.Dropdownlistfor Set Selected When Value Is in Array
How to Convert Utf-8 Byte[] to String
Arraylist VS List≪≫ in C#
What Does the [Flags] Enum Attribute Mean in C#
How to Auto-Generate a C# Class File from a Json String
How to Pass Data (And References) Between Scenes in Unity
How to Detect the Encoding/Codepage of a Text File
How to Post Messages to an Sta Thread Running a Message Pump
Observablecollection Not Noticing When Item in It Changes (Even With Inotifypropertychanged)