为什么我得到这个"无法转换类型"例外?

时间:2018-02-20 09:20:52

标签: c# .net casting .net-core

我有以下代码

public class SortTerm<T> 
{

    public System.Func<T, System.IComparable> Sort;
    public SortDirection Direction;

    public SortTerm(System.Func<T, System.IComparable> sorter, SortDirection direction)
    {
        this.Sort = sorter;
        this.Direction = direction;
    }

    public SortTerm(System.Func<T, System.IComparable> sorter)
        : this(sorter, SortDirection.Ascending)
    { }


    public static SortTerm<T> Create<TKey>(System.Func<T, TKey> sorter, SortDirection direction)
        where TKey : System.IComparable
    {
        return new SortTerm<T>((System.Func<T, System.IComparable>)(object)sorter, direction);
    } // End Constructor 


    public static SortTerm<T> Create<TKey>(System.Func<T, TKey> sorter)
        where TKey : System.IComparable
    {
        return Create<TKey>(sorter, SortDirection.Ascending);
    } // End Constructor 

}

需要将System.Func<T, TKey>转换为System.Func<T, IComparable>

为什么

SortTerm<Db.T_projects>.Create(x => x.name);

工作,而

SortTerm<Db.T_projects>.Create(x => x.id);

提供无效演员

  

InvalidCastException:无法转换类型为&#39; System.Func2 [Db.T_projects,System.Int64]&#39;输入   &#39; System.Func2 [Db.T_projects,System.IComparable]&#39;

当long / Int64定义为

public struct Int64 : IComparable, IComparable<Int64>, IConvertible, IEquatable<Int64>, IFormattable

虽然字符串定义与IComparable没有区别......

public sealed class String : IEnumerable<char>, IEnumerable, IComparable, IComparable<String>, IConvertible, IEquatable<String>, ICloneable

完整性

public partial class T_projects
{
     public long id; // int not null
     public string name; // nvarchar(4000) not null
}

这不应该吗?
更重要的是,如何使这项工作?

注意:
会有一个List<SortTerm<T>>,所以我不能在排序定义中使用TKey。

2 个答案:

答案 0 :(得分:0)

正如RenéVogt在评论中告诉你的那样,这是因为值类型(如Int64)不支持共变量转换,而它适用于引用类型(例如字符串)。

通过将分拣机放入具有匹配签名的委托中来修复它 一个类型转换代表,所以说:

public class SortTerm<T> 
{

    public System.Func<T, System.IComparable> Sort;
    public SortDirection Direction;

    public SortTerm(System.Func<T, System.IComparable> sorter, SortDirection direction)
    {
        this.Sort = sorter;
        this.Direction = direction;
    }

    public SortTerm(System.Func<T, System.IComparable> sorter)
        : this(sorter, SortDirection.Ascending)
    { }


    public static SortTerm<T> Create<TKey>(System.Func<T, TKey> sorter, SortDirection direction)
        where TKey : System.IComparable
    {
        // return new SortTerm<T>((System.Func<T, System.IComparable>)(object)sorter, direction);

        return new SortTerm<T>(delegate (T x) {
            TKey ret = sorter(x);
            return (System.IComparable)ret;
        }, direction);

    } // End Constructor 


    public static SortTerm<T> Create<TKey>(System.Func<T, TKey> sorter)
        where TKey : System.IComparable
    {
        return Create<TKey>(sorter, SortDirection.Ascending);
    } // End Constructor 

}

您可能希望放弃where TKey : System.IComparable限制,因为这不适用于可空类型,例如。

SortTerm<Db.T_projects>.Create(x => x.created);

public partial class T_projects
{
     public long id; // int not null
     public string name; // nvarchar(4000) not null
     public System.DateTime? created; // datetime null
}

作为AFAIK,没有办法

where TKey : System.IComparable or System.Nullable<System.IComparable>

答案 1 :(得分:0)

docs反转方差仅适用于参考类型 - 例如string

  

差异仅适用于参考类型;如果指定值类型   对于变量类型参数,该类型参数对于该变量是不变的   结果构造类型。

所以你可以做到以下几点:

Func<string> myFunc = ...
Func<object> func = myFunc;

但不是这样:

Func<int> myFunc = ...
Func<object> func = myFunc;

要规避这一点,请将id添加到object

Func<object> = () => (object) id;

您的代码中将包含以下内容:

SortTerm<Db.T_projects>.Create(x => (object) x.id);

或在现有代表上创建新代理:

Func<object> = () => myFunc();

在您的代码中对应于此:

SortTerm<Db.T_projects>.Create(new Func<MyType, object>(x => x.id));