C#: How to use generic method with “out” variable

2019-04-06 10:29发布

问题:

I want to create a simple generic function

void Assign<T>(out T result) 
{
  Type type = typeof(T);
  if (type.Name == "String")
  {
     // result = "hello";
  }
  else if (type.Name == "Int32")
  {
     // result = 100;
  } 
  else result = default(T);
}

Usage:

int value;
string text;

Assign(value); // <<< should set value to 100
Assign(text); // <<< should set text to "hello"

My question is how do you program the code to set these values ie. the missing codes in comment section.

Thanks for any help.

回答1:

It looks like in this case maybe you're doing it to try to avoid boxing? Difficult to say without more information, but for this specific example, it'd be much easier and probably less bug-prone to just use method overloading:

void Assign(out string value)
{
   //...
}

void Assign(out int value)
{
   //...
}

For the purposes of learning specifically what is wrong here, you do need to cast a value to an object before casting it to the generic type:

(T)(object)"hello world!";

Which IMO is pretty nasty and should be a last resort - certainly doesn't make your code any cleaner.

Any time you do type-checking of generic parameters, it's a good indication generics are not the right solution to your problem. Doing generic parameter type checks makes your code more complex, not simpler. It makes one method responsible for different behaviors based on type, instead of a series of single methods that are easy to change without accidentally affecting the others. See Single Responsibility Principle.



回答2:

First of all that's a very bad pattern. You shouldn't use this kind of pattern. Maybe if you describe what you really want to achieve there will be better answers.

Code below works, but as I said writing code this way is a bad idea.

    void Assign<T>(out T result) 
    { 
        Type type = typeof(T); 
        if (type.Name == "String") 
        { result = (T) ((object)"hello"); } 
        else if (type.Name == "Int32") 
        { result = (T) ((object)100); } 
        else result = default(T); 
    }

And usage:

        int value;
        string text;

        Assign(out value);
        Assign(out text);


回答3:

public T GetObject<T>(string val)
{
    T _object = default(T);
    _object = (T)Convert.ChangeType(val, typeof(T));
    return _object;
}


回答4:

Here is one way:

static void Assign<T>(out T result) { 
    Type type = typeof(T);
    if (type.Name == "String") {
        result = (T)Convert.ChangeType("hello", typeof(T));
    }
    else if (type.Name == "Int32") {
        result = (T)Convert.ChangeType(100, typeof(T));
    }
    else {
        result = default(T);
    }
}

But this code smells really bad and goes against the point of generics (instead use overloaded methods). I hope this doesn't end up in production code somewhere and is merely for edification.