Eric Yin
Eric Yin

Reputation: 8973

How to use generic declared variable in C#

public static object GetObject(int x)
{
    return new object { };
}
public static object GetObject(string x)
{
    return new object { };
}
public static void ProcessObject<T>(T x) where T : int, string <= got error here: 
{
    object o = GetObject(x);
}

Got error "A type used as a constraint must be an interface, a non-sealed class or a type parameter."

How can I rewrite the code to get it work without write ProcessObject(int x) and ProcessObject(string x) twice?

Upvotes: 1

Views: 600

Answers (5)

Tim S.
Tim S.

Reputation: 56536

So what you have now (according to accepted answer and your comments) is:

public static void ProcessObject<T>(T x)
{
    object o;
    if (typeof(T) == typeof(int))
        o = GetObject((int)(object)x);
    else if (typeof(T) == typeof(string))
        o = GetObject((string)(object)x);
    else
        throw new Exception();
    // do stuff with o
}

I'd recommend making public int and string overloads, but to prevent code duplication, internally call another method:

public static void ProcessObject(int x)
{
    ProcessObject(GetObject(x));
}
public static void ProcessObject(string x)
{
    ProcessObject(GetObject(x));
}
private static void ProcessObject(object o)
{
    // do stuff with o
}

This makes your public methods' input values clear: int and string are the only acceptable types, while still not duplicating your actual logic (// do stuff with o).

You might dislike that the two public ProcessObject methods are duplicates of each other, (on the surface anyway; under the hood, they're calling two different GetObject overloads) but I think it's the best option.

Upvotes: 3

O. R. Mapper
O. R. Mapper

Reputation: 20720

Generally speaking, if your object reacts differently based on the generic type argument, you probably shouldn't be using generics in this case. Generics are great for situations where you want to do always the same thing, no matter what the actual type used.

Therefore, generic constraints will only allow you to list one base class for a type argument. Any actual types passed to the respective type arguments are meant to be a part of the given inheritance hierarchy starting with the base class you specified, so users of your class can specify any type that matches the base class or any of its subclasses.

At the same time, you, the author of the generic class, can safely assume that the specified type has (at least) the interface of the base class indicated by the constraint. Hence, you may access any members of the base class.

If you want to allow either string or int, imagine what members that could be. Both are derived directly from System.Object, hence the restriction would make no sense as it is no restriction; every type is derived from System.Object.

Summarizing, if you really want to treat string and int differently, this is definitely a case for offering two overloads rather than one generic class.

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726479

You cannot do what you are trying to do: first, it is not possible to list several classes in a generic constraint; second, the type that you can put in a constraint must be such that you could inherit it (or implement it if it is an interface). Both int and string fail this check. In cases like this, you would be better off with two separate overloads.

Upvotes: 2

GSerjo
GSerjo

Reputation: 4778

it's impossible in C# take a look on Constraints on Type Parameters. Try to use dynamic

Upvotes: 1

oleksii
oleksii

Reputation: 35895

Just remove the where part

public static void ProcessObject<T>(T x) 
{
    object o = GetObject(x);
}

And also don't use object in your other methods, instead use T

Upvotes: 1

Related Questions