Reputation: 1245
I want to create a method that can only take a double
as an argument.
If I write it like this:
public static void Foo(double d)
{
// ...
}
Then we can call Foo
with ints, floats, doubles, etc. Like this:
public static void Main()
{
Foo(34); // int
Foo(1.3454365F); // float
Foo(34.12); // double
}
I tried to create a generic method that can only take a double
as a parameter, like this:
public static void Foo<T>(T t) where T : double
{
// ...
}
But type double
can not be used as a constraint.
How can I achieve this?
Upvotes: 1
Views: 100
Reputation: 7684
You can devise some types with implicit operators such that overload resolution will fail to decide a winner for some types but not others:
struct EvilDoubleWrapper
{
public double Value { get; }
public EvilDoubleWrapper(double value)
{
Value = value;
}
public static implicit operator EvilDoubleWrapper(double value) => new EvilDoubleWrapper(value);
public static implicit operator EvilDoubleWrapper(int value)
{
// If the program changes in such a way that this conversion is allowed to occur,
// we should at a minimum raise an assertion
Trace.Assert(true);
return default;
}
}
struct EvilOtherWrapper
{
public static implicit operator EvilOtherWrapper(int value) => default;
}
static void Main(string[] args)
{
Foo(1.23d); // Works
Foo(1); // Error CS0121: The call is ambiguous
}
static void Foo(EvilDoubleWrapper d)
{
// Use d.Value as your double
}
static void Foo(EvilOtherWrapper o)
{
// Does nothing; only exists to fault the overload resolver
}
Neither of EvilDoubleWrapper
nor EvilOtherWrapper
is "better" than other other for overload resolution, and since there's an implicit conversion from int
to both of them, overload resolution will fail. But there is only one implicit conversion from double
to either of those, so overload resolution will successfully pick that one. Define implicit conversions for other built-in conversions that you want to forbid as well -- there's a rather small, closed set of such conversions listed here.
Upvotes: 1