Вызов методов с разными сигнатурами из метода, который получает параметр типа делегата - PullRequest
1 голос
/ 30 сентября 2011

У меня есть универсальный метод (ParseTo) для разбора строк на другие типы. Этот метод получает параметр типа делегата, который содержит метод для выполнения:

public delegate bool ParseToDelegate<T>(string value, out T result);

public static T? ParseTo<T>(this string value, 
    ParseToDelegate<T> method) where T : struct
{
    T result;
    if (String.IsNullOrWhiteSpace(value)) return null;
    if (method(value, out result)) return result;
    return null;
}

Это прекрасно работает, потому что подпись TryParse одинакова для всех базовых типов.

var s = "1234,567";
Console.WriteLine(s.ParseTo<int>(int.TryParse)); //Error. Returns null
Console.WriteLine(s.ParseTo<decimal>(decimal.TryParse)); //Ok

var d = "14/05/2011 19:45";
Console.WriteLine(d.ParseTo<DateTime>(DateTime.TryParse)); //Ok

var g = Guid.NewGuid().ToString();
Console.WriteLine(g.ParseTo<Guid>(Guid.TryParse)); //Ok

Моя проблема: теперь я хотел бы расширить этот метод для поддержки разных культур ... Но числовые типы и типы дат имеют разные подписи:

bool TryParse(string s, NumberStyles style, IFormatProvider provider, out int result);
bool TryParse(string s, IFormatProvider provider, DateTimeStyles styles, out DateTime result);

Есть ли способ «отобразить» полученного делегата и вызвать правильный метод? Примерно так:

if (typeof(T) == typeof(DateTime))
{
    //Call DateTime.TryParse(string s, IFormatProvider provider, 
        //DateTimeStyles styles, out DateTime result)
}
else
{
    //Call DateTime.TryParse(string s, 
    //NumberStyles style, IFormatProvider provider, out int result);
}

Ответы [ 2 ]

0 голосов
/ 03 октября 2011

Похоже, вы ищете что-то похожее на то, что вы уже делаете.В этот момент проще всего было бы сделать второй и третий параметры также общими.

public delegate bool ParseToDelegate<T,U,K>(string value, U secondOption, K thirdOption, out T result);

public static T? ParseTo<T, U, K>(this string value, U second, K third, ParseToDelegate<T,U, K> method) where T : struct
{
    T result;
    if (String.IsNullOrWhiteSpace(value)) return null;
    if (method(value, second, third, out result)) return result;
    return null;
}

Однако проблема в том, что сигнатура места вызова метода начинает становиться довольно неприятной и это в значительной степени зависит от вызывающей стороны, знающей структуру делегата и для чего вообще нужны общие параметры.

someDateString.ParseTo<DateTime, IFormatProvider, DateTimeStyles>
            (CultureInfo.CurrentCulture.DateTimeFormat, 
             DateTimeStyles.AssumeUniversal, 
             DateTime.TryParse);

Чтобы немного это облегчить, вы можете просто обернуть этивызовы в вызовах с особым типом и вместо этого представляют их как методы расширения.

public static DateTime? ParseToDateTime(this string value, IFormatProvider provider, DateTimeStyles style)
{
    return ParseTo<DateTime, IFormatProvider, DateTimeStyles>(value, provider, style, DateTime.TryParse);
}

Это облегчит вызов вызывающему, но основополагающие интуиции могут все еще быть немного запутанными и должны определенно документироваться.хорошо.

someDateString.ParseToDateTime(CultureInfo.CurrentCulture.DateTimeFormat, 
                               DateTimeStyles.AssumeUniversal);
0 голосов
/ 30 сентября 2011

Возможно, вы заново изобретаете колесо - Convert.ChangeType() уже делает почти то, что вам нужно - пример из MSDN:

Temperature cool = new Temperature(5);
Type[] targetTypes = { typeof(SByte), typeof(Int16), typeof(Int32),
                        typeof(Int64), typeof(Byte), typeof(UInt16),
                        typeof(UInt32), typeof(UInt64), typeof(Decimal),
                        typeof(Single), typeof(Double), typeof(String) };
CultureInfo provider = new CultureInfo("fr-FR");

foreach (Type targetType in targetTypes)
{
    try {
    object value = Convert.ChangeType(cool, targetType, provider);
    Console.WriteLine("Converted {0} {1} to {2} {3}.",
                        cool.GetType().Name, cool.ToString(),
                        targetType.Name, value);
    }
    catch (InvalidCastException) {
    Console.WriteLine("Unsupported {0} --> {1} conversion.",
                        cool.GetType().Name, targetType.Name);
    }                     
    catch (OverflowException) {
    Console.WriteLine("{0} is out of range of the {1} type.",
                        cool, targetType.Name);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...