Why am I getting an exception "Cannot exclude object of type"?
I have the following code
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 } Who needs to drop System.Func<T, TKey> to System.Func<T, IComparable>
Why
SortTerm<Db.T_projects>.Create(x => x.name); a
SortTerm<Db.T_projects>.Create(x => x.id); provides Invalid Cast
InvalidCastException: Unable to use an object of type "System.Func2 [Db.T_projects, System.Int64]" to enter 'System.Func2 [Db.T_projects, System.IComparable]'.
when long / int64 is defined as
public struct Int64 : IComparable, IComparable<Int64>, IConvertible, IEquatable<Int64>, IFormattable While the string is not defined as IComparable ...
public sealed class String : IEnumerable<char>, IEnumerable, IComparable, IComparable<String>, IConvertible, IEquatable<String>, ICloneable for completeness
public partial class T_projects { public long id; // int not null public string name; // nvarchar(4000) not null } Doesn't that work?
And more importantly, how to do this?
Note:
There will be a List<SortTerm<T>>, so I cannot just use TKey in the sort definition.
As RenΓ© Vogt already told you in the comments, this is because co-variant conversion is not supported for value types (like Int64), whereas it works for reference types (like string).
Fix this by putting the sorter on the delegate with the appropriate signature.
The order of the delegate type, so to speak:
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 } You might want to abandon the where TKey : System.IComparable constraint, as this will not work for types with a null value, for example.
SortTerm<Db.T_projects>.Create(x => x.created); for
public partial class T_projects { public long id; // int not null public string name; // nvarchar(4000) not null public System.DateTime? created; // datetime null } like afaik there is no way
where TKey : System.IComparable or System.Nullable<System.IComparable> Compared to docs, contra-variance only works for reference types - for example. string
Deviation applies only to reference types; if you specify a value type for a variant type parameter, this type parameter is invariant for the resulting constructed type.
So you can do the following:
Func<string> myFunc = ... Func<object> func = myFunc; but not this:
Func<int> myFunc = ... Func<object> func = myFunc; To work around this, set the id field to object :
Func<object> = () => (object) id; which will look like this:
SortTerm<Db.T_projects>.Create(x => (object) x.id); or create a new delegate from the existing one:
Func<object> = () => myFunc(); which matches this in your code:
SortTerm<Db.T_projects>.Create(new Func<MyType, object>(x => x.id));