inna
inna

Reputation: 35

C# how to force generic argument to be type

i have generic method. i want generic method to limit one type. problem is derived type not to be allowed - i do not want this. example codes:

public static T Generate<T>(T input)
    where T : Operation // ALLOWS BinaryOperation - NOT WANT THIS
{
    //...
}

how to do what I request?

Upvotes: 1

Views: 5106

Answers (2)

Felix K.
Felix K.

Reputation: 6281

It's not possible to force a method to accept only one specific type like Operation if the type is not a struct or a sealed class.

Let's me show this in a example why this won't work anyway:

public void Generate<T>(Operation op) 
    // We assume that there is the keyword "force" to allow only Operation classes
    // to be passed
    where T : force Operation
{ ... }

public void DoSomething()
{
    Generate(new BitOperation()); // Will not build
    // "GetOperation" retrieves a Operation class, but at this point you dont
    // know if its "Operation" or not
    Operation op = GetOperation();
    Generate(op); // Will pass
}

public Operation GetOperation() { return new BitOperation(); }

As you can see it will be easy to pass a BitOperation even when there is a restriction.

Solution

There is only one solution beside the others mentioned above ( struct, sealed ): Runtime Check. You can write yourself a little helper method for this.

public class RuntimeHelper
{
    public static void CheckType<T>(this Object @this)
    {
        if (typeof(T) != @this.GetType())
            throw new ....;
    }
}

Usage

public void Generate(Operation op)
{
    op.CheckType<Operation>(); // Throws an error when BitOperation is passed
}

Little Note

If you want to speed up the helper you could use a generic class RuntimeHelper<T> with a static readonly type variable which has the type of T.

When you're doing this you cannot longer use extension methods so the call would look like this:

RuntimeHelper<Operation>.CheckType(op);

Upvotes: 0

Reed Copsey
Reed Copsey

Reputation: 564413

problem is derived type not to be allowed

There is no way to enforce this constraint, without checking it at runtime. Doing so would be a violation of the Liskov Substitution Principle, which states that any type should allow you to pass in a derived type without restriction.

If you must enforce this, it will only work with a runtime check, like:

public static T Generate<T>(T input)
    where T : Operation // ALLOWS BinaryOperation - NOT WANT THIS
{
    // Checks to see if it is "Operation" (and not derived type)
    if (input.GetType() != typeof(Operation))
    {
        // Handle bad case here...
    }

    // Alternatively, if you only want to not allow "BinaryOperation", you can do:
    if (input is BinaryOperation)
    {
        // Handle "bad" case of a BinaryOperation passed in here...
    }
}

Note that, in this case, there's really no reason to make it generic, as the same code would work as:

public static Operation Generate(Operation input)
{ // ...

Upvotes: 10

Related Questions