【问题标题】:Checking if some function parameters data types are equal due compilation on C#检查某些函数参数数据类型是否相等,因为在 C# 上编译
【发布时间】:2010-02-25 21:06:43
【问题描述】:

我有一些示例数据:

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 -&gt; intstring -&gt; stringDateTime? -&gt; 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 =&gt; t.INT, "SomeSting");,编译器会报告错误: 类型“string”不能用作泛型类型或方法“Task.Marry(System.Linq.Expressions.Expression>, T2)”中的类型参数“T2”。没有从 'string' 到 'int' 的隐式引用转换。

但此解决方案不适用于null。当我调用Marry(t =&gt; t.NULLABLEDATETIME, null); 时,编译器会说: 方法“Marry(System.Linq.Expressions.Expression>, T2)”的类型参数无法从用法中推断出来。尝试明确指定类型参数。

为什么?我已经知道数据类型:DateTime?。我不想明确调用Marry&lt;DateTime?&gt;(t =&gt; t.NULLABLEDATETIME, null);。我该怎么做 - 或者有其他方法可以在编译期间检查某些函数参数类型?

【问题讨论】:

    标签: c# generics parameters types constraints


    【解决方案1】:

    您为什么不简单地将T1T2 替换为单个泛型类型参数?然后不需要推断第二个参数类型 - 无论如何它不必是,因为它必须与第一个参数的类型相同。

    看起来像这样:

    变体 1

    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?'),可以curry方法:

    变体 2

    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 的可读性不太高,并且使用大量嵌套的泛型类型会使事情……可读性降低。具有基本相同行为但错误消息较短的较长变体可能如下所示:

    变体 3

    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?'
    

    该错误消息更具体一些。我认为变体 1 的错误消息就足够了,这就是我会使用的(KISS 和所有) - 但如果你真的想要那个转换错误消息,变体 3 具有最容易理解的(如果更长的话)实现和最友好的错误信息。

    【讨论】:

    • 因为现在调用函数时参数错误 Marry(t => t.NULLABLEDATETIME, "SomeString");编译器说:无法从用法中推断方法 'Lambda.Db.Task.Task.Marry(System.Linq.Expressions.Expression>, T)' 的类型参数。尝试明确指定类型参数。如您所见,我们仍然收到此消息。我想让编译器说:没有从 'string' 到 'DateTime?' 的隐式引用转换。
    • 然而,这并不是一个严重的错误。使用 T1+T2 方法,无法解析正确的情况(非正式地:T1 字符串,T2 null),而使用此方法,虽然错误消息可能不理想,但更正确的情况有效,而错误的情况则不行。
    • 另外,您看到的错误消息是 linq 的标准。例如,尝试:Enumerable.Concat(new[]{3},new[]{"test"}); 会导致相同的错误消息。
    • 如果你真的希望错误消息给你一个“铸造”错误,我已经添加了两个变体来做到这一点。
    【解决方案2】:

    你可以将 null 转换为某种类型

    (string)null, (object)null
    

    【讨论】:

      猜你喜欢
      • 2018-12-26
      • 2021-03-18
      • 1970-01-01
      • 2013-05-31
      • 2021-11-13
      • 1970-01-01
      • 2013-09-29
      • 2021-02-03
      • 1970-01-01
      相关资源
      最近更新 更多