通用方法中的条件类型

Hug*_*ira 11 c# generics variance

考虑以下(大大简化)代码:

public T Function<T>() {
    if (typeof(T) == typeof(string)) {
        return (T) (object) "hello";
    }
    ...
}
Run Code Online (Sandbox Code Playgroud)

首先施展到object那时是荒谬的T.但编译器无法知道先前的测试确保T类型string.

在C#中实现这种行为的最优雅,惯用的方式是什么(包括摆脱愚蠢typeof(T) == typeof(string),因为T is string不能使用)?


附录: .net中没有返回类型差异,因此你不能让函数重载来输入字符串(顺便说一下,这只是一个例子,但是多态性中关联结束重定义的一个原因,例如UML,可以不能用c#完成.显然,以下将是伟大的,但它不起作用:

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

public string Function<string>() {
    return "hello";
}
Run Code Online (Sandbox Code Playgroud)

具体示例1:因为针对特定类型测试的通用函数不是通用的,所以有几次攻击,我将尝试提供更完整的示例.考虑Type-Square设计模式.以下是一个片段:

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);
  }
}
Run Code Online (Sandbox Code Playgroud)

具体示例2:考虑解释器设计模式:

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

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

现在让我们在Execute中使用泛型来允许调用者强制返回类型:

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;
  }
}
Run Code Online (Sandbox Code Playgroud)

Ree*_*sey 6

如果您在通用方法中进行这些类型的检查,我会重新考虑您的设计.该方法显然不是真正的通用 - 如果是,你不需要特定的类型检查......

这种情况通常可以通过重新设计更清晰地处理.一种替代方案通常是提供适当类型的过载.其他避免类型特定行为的设计方案也存在,例如Richard Berg提出的传递代表的建议.

  • 我同意一个非常笼统/模糊的意思,但这根本不回答这个问题.有时,现实要求通用和特定功能在同一堆栈帧共存.(你可以随时复制/粘贴通用部分,但是这比IMO中的任何提议都要糟糕)幸运的是,C#支持延迟执行,这允许我的答案中看到的hacky-but-workingable模式. (2认同)
  • @Richard:我认为这是所写问题的唯一*有效答案.究竟如何调用者应该理解对于特定类型行为不同的泛型方法的语义?也许如果OP已经解释了他真正想要做的事情,那么有人可以提供并解释更好的选择. (2认同)