【问题标题】:Call method with templated parameter使用模板参数调用方法
【发布时间】:2018-06-03 02:43:00
【问题描述】:

我有一个通用方法:

protected override void Work<T>(T requestResult)
{
    ...
    CallsSomeOtherMethodFromOtherClass(requestResult);
}

但 Xamarin 不会让我这样做。
它说它不能将 requestResult 转换为字符串(CallsSomeOtherMethodFromOtherClass 将字符串作为参数)。

但在这个特定的覆盖中,我确信类型 T 将是一个字符串。

我应该改变什么让编译器让我调用该方法:

CallsSomeOtherMethodFromOtherClass(string);

【问题讨论】:

  • 如果你确定 T 总是一个字符串,为什么方法定义为泛型方法?编译器不知道 T 始终是一个字符串。
  • @mm8 在这个特殊的覆盖中,我知道它会是一个字符串。但在其他一些覆盖它不会!
  • 好吧,那么您需要尝试在runtime 将requestResult 转换为字符串。就编译器而言,requestResult 可能是任何类型 T。
  • @mm8 我试过了! -> 工作((字符串)请求结果);但它说它不能将 T 转换为字符串
  • 编译时还是运行时?你看到我的代码示例了吗...?也许你应该试试看。

标签: c# oop templates xamarin


【解决方案1】:

请注意,此代码是在没有 IDE 的情况下编写的,并且尚未编译。不要复制粘贴。

您可以做的是向泛型添加一个约束。所以 T 继承自 X。 在这种情况下,T 必须从接口 IWorkUnit 继承。

protected override void Work<T>(T requestResult) where T : IWorkUnit
{
    DoWork(requestResult);
}

然后 DoWork 接受 IWorkUnit 作为参数。 IWorkUnit 将具有您可能想要的任何属性。

完整示例:

protected override void Work<T>(T requestResult) where T : IWorkUnit
{
    switch(requestResult.TypeOfWork) {
        default:
        case EWorkType.Test:
            DoTestWork(requestResult);
        break;

        case EWorkType.Work:
            DoWork(requestResult);
        break;
    }
}

或者,您可以只使用模式匹配。我建议向 IWorkUnit 添加一个枚举,它显示工作单元的工作类型。 然后做一个工厂来决定应该用什么方法来处理请求,像这样:

protected override void Work<T>(T requestResult)
{
    switch(requestResult) {
        case ITestUnit testUnit:
            DoTestWork(testUnit);
        break;

        case string workStr:
            DoWork(workStr);
        break;

        default:
            //Show error
        break;
    }
}

【讨论】:

  • 感谢您的回答。必须更改 doWork() 原型以接受 IWorkUnit 类型吗?没有?
  • 会,但 IWorkUnit 只是一个例子。如果您希望保持方法的签名完整,可以使用最后一个示例。
  • 我很难理解您的案例说明。 workStr 的价值是多少?
  • workStr 将被 requestResult 强制转换为字符串。只有在 requestResult 可以转换为字符串时才会执行这种情况:)
【解决方案2】:

由于Work 被定义为泛型方法,编译器无法知道requestResult 将始终是string。它可以是任何类型的T

如果您“确定T 类型将是string”,则不妨将方法定义为非泛型void Work(string requestResult)。定义一个只接受strings 的泛型方法是没有意义的。

如果由于某种原因无法做到这一点,您可以按照@Fildor 的建议在运行时尝试将requestResult 转换为string。这就是您可以在 C# 和 Visual Studio 的早期 (C#6-) 版本中执行此操作的方法:

protected override void Work<T>(T requestResult)
{
    string s = requestResult as string;
    if (s != null)
    {
        CallsSomeOtherMethodFromOtherClass(s);
    }
}

【讨论】:

  • work(...) 方法在这个特定的覆盖中采用一个字符串。但在其他具体实现中,它将是其他类型。
  • 那么,正如我在回答中解释的那样,您将被抛在一边。
  • 是的。编译器不喜欢这种转换:“从 T 到字符串的不可能转换”
  • 什么版本的 Visual Studio...?这显然对我有用。
  • 请提供其他人需要的所有代码,以便能够从头开始重现您的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-17
  • 2021-10-01
  • 2017-06-26
  • 2013-03-07
相关资源
最近更新 更多