Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional typing in generic method

Consider the following (heavily simplified) code:

public T Function<T>() {
    if (typeof(T) == typeof(string)) {
        return (T) (object) "hello";
    }
    ...
}

It's kind of absurd to first cast to object, then to T. But the compiler has no way of knowing that the previous test assured T is of type string.

What is the most elegant, idiomatic way of achieving this behavior in C# (which includes getting rid of the stupid typeof(T) == typeof(string), since T is string can't be used)?


Addendum: There is no return type variance in .net, so you can't make a function overload to type string (which, by the way, is just an example, but one reason why association end redefinition in polymorphism, e.g. UML, can't be done in c#). Obviously, the following would be great, but it doesn't work:

public T Function<T>() {
    ...
}

public string Function<string>() {
    return "hello";
}

Concrete Example 1: Because there's been several attacks to the fact that a generic function that tests for specific types isn't generic, I'll try to provide a more complete example. Consider the Type-Square design pattern. Here follows a snippet:

public class Entity {
  Dictionary<PropertyType, object> properties;

  public T GetTypedProperty<T>(PropertyType p) {
    var val = properties[p];

    if (typeof(T) == typeof(string) {
      (T) (object) p.ToString(this);  // magic going here
    }

    return (T) TypeDescriptor.GetConverter(typeof(T)).ConvertFrom(val);
  }
}

Concrete Example 2: Consider the Interpreter design pattern:

public class Expression {
  public virtual object Execute() { }
}

public class StringExpression: Expression {
  public override string Execute() { }    // Error! Type variance not allowed...
}

Now let's use generics in Execute to allow the caller to force a return type:

public class Expression {
  public virtual T Execute<T>() { 
    if(typeof(T) == typeof(string)) {  // what happens when I want a string result from a non-string expression?
       return (T) (object) do_some_magic_and_return_a_string();
    } else if(typeof(T) == typeof(bool)) { // what about bools? any number != 0 should be True. Non-empty lists should be True. Not null should be True
       return (T) (object) do_some_magic_and_return_a_bool();
    }
  }
}

public class StringExpression: Expressiong {
  public override T Execute<T>() where T: string {   
    return (T) string_result;
  }
}
like image 689
Hugo Sereno Ferreira Avatar asked Feb 15 '10 22:02

Hugo Sereno Ferreira


People also ask

How do you add a condition in TypeScript?

Syntax: We can create the conditional types with the used of ternary operator and extends in TypeScript. Type1 extends Type2 ? for One value : for different value; Here extend works as compare function which checks is Type1 have properties of Type2 if yes then it jumps to true branch else in the false branch.

What are conditional types How do you create them?

Conditional types help describe the relation between the types of inputs and outputs. When the type on the left of the extends is assignable to the one on the right, then you'll get the type in the first branch (the “true” branch); otherwise you'll get the type in the latter branch (the “false” branch).

How do you write a conditional statement in TypeScript?

Following is an example TypeScript code to demonstrate if conditional statement. var a:number = 1 var b:number = 3 if(a == 1){ console. log("value of a is 1.") } else { console. log("value of a is not 1.") } if(a == b){ console.

How do you check TypeScript type?

In Typescript, we have three ways to work with it using: typeof: the keyword helps to check values types, like boolean, string, number, etc. instanceof: the keyword to compare the object instance with a class constructor. type guards: The powerful way to check types using typescript feature language.


1 Answers

If you're making these types of checks in a generic method, I'd rethink your design. The method is obviously not truly generic - if it were, you wouldn't need specific type checking...

Situations like this typically can be handled more cleanly by a redesign. One alternative is often to provide an overload of the appropriate type. Other design alternatives which avoid the type-specific behavior exist, as well, such as Richard Berg's suggestion of passing in a delegate.

like image 141
Reed Copsey Avatar answered Oct 19 '22 19:10

Reed Copsey