我有一些示例数据:
public struct Task
{
public int INT;
public string STRING;
public DateTime? NULLABLEDATETIME;
}
功能,使用它:
public KeyValuePair<Expression<Func<Task, object>>, object> Marry(Expression<Func<Task, object>> key, object value)
{
return new KeyValuePair<Expression<Func<Task, object>>, object>(key, value);
}
以下是函数调用的示例:
Marry(t => t.INT, 1984);
Marry(t => t.NULLABLEDATETIME, DateTime.Now);
Marry(t => t.STRING, "SomeSting");
此代码有效,没问题。不幸的是,我们也可以调用下面的函数,因为String和int都是从对象类继承的:
Marry(t => t.INT, "SomeSting");
我想说编译器,第一个和第二个参数具有相同的数据类型:int -> int
,string -> string
,DateTime? -> DateTime?
并在编译期间检查它。我试过这个:
public KeyValuePair<Expression<Func<Task, T1>>, T2> Marry<T1, T2>(Expression<Func<Task, T1>> key, T2 value)
where T2 : T1
{
return new KeyValuePair<Expression<Func<Task, T1>>, T2>(key, value);
}
这几乎可以工作,如果我尝试输入错误的数据,如Marry(t => t.INT, "SomeSting");
,编译器会报错:
类型'string'不能在泛型类型或方法'Task.Marry(System.Linq.Expressions.Expression&gt;,T2)'中用作类型参数'T2'。没有从'string'到'int'的隐式引用转换。
但是此解决方案不适用于null
。当我调用Marry(t => t.NULLABLEDATETIME, null);
时,编译器说:
方法'Marry(System.Linq.Expressions.Expression&gt;,T2)'的类型参数无法从用法中推断出来。尝试明确指定类型参数。
为什么呢?我已经知道数据类型:DateTime?
。我不想明确地呼叫Marry<DateTime?>(t => t.NULLABLEDATETIME, null);
。我该怎么做 - 还是有另一种方法可以在编译期间检查一些函数参数类型?
答案 0 :(得分:3)
为什么不简单地用一个通用类型参数替换T1
和T2
?然后不需要推断第二个参数类型 - 它不必无论如何,因为它必须与第一个参数的相同。
看起来像这样:
public KeyValuePair<Expression<Func<Task, T>>, T>
Marry<T>(
Expression<Func<Task, T>> key,
T value) {
return new KeyValuePair<Expression<Func<Task, T>>, T>(key, value);
}
我不建议这样做,但是如果你希望类型推断“贪婪地”仅根据第一个参数来确定表达式的类型(这样你就会得到错误“无法从'string'转换为' DateTime?'),你可以讨论方法:
public static Func<T, KeyValuePair<Expression<Func<Task, T>>, T> >
Marry<T>(
Expression<Func<Task, T>> key) {
return (value=>new KeyValuePair<Expression<Func<Task, T>>, T>(key, value));
}
//usage:
Marry(t => t.NULLABLEDATETIME)("test");
//error: Delegate 'System.Func<System.DateTime?,System.Collections.Generic.KeyValuePair<System.Linq.Expressions.Expression<System.Func<UserQuery.Task,System.DateTime?>>,System.DateTime?>>' has some invalid arguments
// - Argument 1: cannot convert from 'string' to 'System.DateTime?'
该错误消息基本上涵盖了它。但是,API不太可读,并且使用大量嵌套的泛型类型会使事情变得不那么可读。具有基本相同行为但较短错误消息的较长变体可能如下所示:
public class MarriagePartner<T> {
readonly Expression<Func<Task, T>> key;
public MarriagePartner(Expression<Func<Task, T>> key) { this.key = key; }
public KeyValuePair<Expression<Func<Task, T>>, T> With(T value) {
return new KeyValuePair<Expression<Func<Task, T>>, T>(key, value);
}
}
public static MarriagePartner<T> Marry2<T>(Expression<Func<Task, T>> key) {
return new MarriagePartner<T>(key);
}
//Usage:
Marry2(t => t.NULLABLEDATETIME).With("test");
//error: The best overloaded method match for 'UserQuery.MarriagePartner<System.DateTime?>.With(System.DateTime?)' has some invalid arguments
// - Argument 1: cannot convert from 'string' to 'System.DateTime?'
该错误消息更具体一些。我认为Variant 1的错误消息就足够了,而且它是我使用的(KISS和所有) - 但是如果你真的想要那个转换错误消息,Variant 3有最容易理解的(如果更长)实现和大多数友好的错误信息。
答案 1 :(得分:1)
您可以将null转换为某种类型
(string)null, (object)null