36

我想做一个方法:

object Execute()
{
    return type.InvokeMember(..);
}

接受一个通用参数:

T Execute<T>()
{
    return Execute() as T;

    /* doesn't work:
    The type parameter 'T' cannot be used with the 'as' operator because
    it does not have a class type constraint nor a 'class' constraint */

    // also neither typeof(T), nor T.GetType() are possible

    return (T) Execute(); // ok
}

但我认为 operatoras将非常有用:如果结果类型不是T方法将返回null,而不是异常!有可能吗?

4

5 回答 5

73

您需要添加

where T : class

到您的方法声明,例如

T Execute<T>()  where T : class
{

顺便说一句,作为建议,通用包装器并没有真正增加太多价值。调用者可以写:

MyClass c = whatever.Execute() as MyClass;

或者如果他们想失败:

MyClass c = (MyClass)whatever.Execute();

通用包装器方法如下所示:

MyClass c = whatever.Execute<MyClass>();

所有三个版本都必须指定完全相同的三个实体,只是顺序不同,因此没有一个更简单或更方便,但是通用版本隐藏了正在发生的事情,而“原始”版本每个都清楚地表明是否存在是一个 throw 或一个null.

(如果您的示例从您的实际代码简化,这可能与您无关)。

于 2009-03-28T20:29:59.770 回答
14

您不能将as运算符与没有限制的泛型类型一起使用。由于as运算符使用 null 来表示它不是该类型,因此您不能在值类型上使用它。如果要使用, 必须obj as TT引用类型。

T Execute<T>() where T : class
{
  return Execute() as T;
}
于 2009-03-28T20:31:35.177 回答
9

这段代码是as关键字的异常安全替换:

return Execute() is T value ? value : default(T)

它使用 C# 7 引入的模式匹配功能。如果您不想将泛型参数限制为引用类型,请使用它

于 2018-10-15T10:47:16.103 回答
1

似乎您只是添加了一个包装器方法来转换为用户想要的类型,因此只会增加执行的开销。对于用户来说,写

int result = Execute<int>();

int result = (int)Execute();

您可以使用out修饰符将结果写入调用者范围内的变量中,并返回一个布尔标志来判断它是否成功:

bool Execute<T>(out T result) where T : class
{
    result = Execute() as T;
    return result != null;
}
于 2009-03-28T20:47:09.587 回答
1

Execute() 是否有可能返回值类型?如果是这样,那么您需要 Earwicker 的类类型方法和值类型的另一种通用方法。可能看起来像这样:

Nullable<T> ExecuteForValueType<T> where T : struct

该方法内部的逻辑会说

object rawResult = Execute();

然后,您必须获取 rawResult 的类型并查看它是否可以分配给 T:

Nullable<T> finalReturnValue = null;

Type theType = rawResult.GetType();
Type tType = typeof(T);

if(tType.IsAssignableFrom(theType))
{
    finalReturnValue = tType;     
}

return finalReturnValue;

最后,让您的原始 Execute 消息找出 T 具有哪个(类或结构类型),并调用适当的实现。

注意:这是粗略的记忆。大约一年前我这样做了,可能不记得每个细节。不过,我希望为您指明大方向会有所帮助。

于 2009-03-28T20:47:26.933 回答