ndogac
ndogac

Reputation: 1245

Create a method that can only take T as a parameter

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

Answers (1)

Jeff
Jeff

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

Related Questions