Проверка, равны ли некоторые типы данных параметров функции из-за компиляции на C # - PullRequest
1 голос
/ 25 февраля 2010

У меня есть пример данных:

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' нельзя использовать в качестве параметра типа 'T2' в универсальном типе или методе 'Task.Marry (System.Linq.Expressions.Expression>, T2)'. Не существует неявного преобразования ссылок из 'string' в 'int'.

Но это решение не работает с null. Когда я звоню Marry(t => t.NULLABLEDATETIME, null);, компилятор говорит: Аргументы типа для метода 'Marry (System.Linq.Expressions.Expression>, T2)' не могут быть выведены из использования. Попробуйте указать аргументы типа явно.

Почему? Я уже знаю тип данных: DateTime?. Я не хочу явно звонить Marry<DateTime?>(t => t.NULLABLEDATETIME, null);. Как я могу это сделать - или есть другой способ проверить некоторые типы параметров функции во время компиляции?

Ответы [ 2 ]

3 голосов
/ 25 февраля 2010

Почему бы вам просто не заменить T1 и T2 одним параметром универсального типа? Тогда второй тип параметров не нужно выводить - каким он не должен быть, так как он должен быть идентичен первому параметру.

Это будет выглядеть так:

Вариант 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);
}

Я не рекомендую этого, но если вы хотите, чтобы вывод типа «жадно» определял тип выражения, основываясь исключительно на первом параметре (чтобы вы получили ошибку), вы не можете преобразовать из «строки» в « DateTime? '), Вы можете карри метод:

Вариант 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 имеет наиболее понятную (если дольше) реализацию и наиболее дружественный сообщение об ошибке.

1 голос
/ 25 февраля 2010

Вы можете привести null к какому-либо типу

(string)null, (object)null
...