2017-01-17 21 views
1

Я ищу способ избежать подробных перегрузок в случае метода, который 1) всегда будет преобразовывать параметр в строку и 2) должен быть доступен для передачи других типов в качестве параметра.Как избежать перегрузки методов для нескольких типов параметров (иначе, чем с помощью параметра объекта)?

Как всегда картина сниппет стоит тысячи слов и нашел следующее решение соотв. Пример: (т.е. используя параметр объекта, который is cast to IFormattable для passing invariant culture)

public static string AppendHexSuffix(this object hexNumber) 
{ 
    string hexString = (hexNumber as IFormattable)? // Cast as IFormattable to pass inv cul 
     .ToString(null, CultureInfo.InvariantCulture) ?? hexNumber.ToString(); 
    if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture) 
     && !hexString.EndsWith("h", true, CultureInfo.InvariantCulture)) 
    { 
     hexString += "h"; // Append hex notation suffix, if missing prefix/suffix 
    } 
    return hexString; 
} 

Хотя, насколько я проверил, это, кажется, работает нормально (поправьте меня, если я что-то не хватает), верхний код не выглядит особенно прямолинейным для меня и предпочел бы более интуитивно понятное решение.

Окончательный Вопрос: есть ли другие более элегантный способ, как решить эту 1) без использования подхода верхнего объекта параметра и 2) без явного объявить перегрузку для каждого типа?

Примечание: верхний фрагмент кода необходимо принимать строго в качестве примера, так как if -statement части, имеет смысл только в случае «реальной» строка передается в качестве параметра.


EDIT: После принятия во внимание ответы + комментарии у меня есть, и после еще нескольких испытаний, следующее окончательное внедрение, кажется, лучше всего подходит для моего случая:

/// <summary> 
/// Converts any type to string and if hex notation prefix/suffix is missing 
/// yet still a valid hex number, then appends the hex suffix 
/// </summary> 
/// <param name="hexNumber">Takes a string, decimal and other types as parameter</param> 
/// <returns>Returns input object content as string with hex notation</returns> 
public static string AppendHexSuffix<T>(this T hexNumber) 
{ 
    // Cast as IFormattable to pass hex format ("X") & invariant culture 
    var hexString = (hexNumber as IFormattable)? 
     .ToString("X", CultureInfo.InvariantCulture).Trim() ?? hexNumber.ToString().Trim(); 
    int unused; 
    if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture) 
     && !hexString.EndsWith("h", true, CultureInfo.InvariantCulture) 
     && int.TryParse(// No hex prefix/suffix, but still a valid hexadecimal number 
      hexString, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out unused)) 
    { 
     hexString += "h"; 
    } 
    return hexString; 
} 

При этом он также должен игнорировать параметры/объекты, где шестнадцатеричный формат не имеет смысла, как указано в комментарии от @InBetween. Примечательная ошибка: забыл формат «X» для первого вызова .ToString().

+2

'AppendHexSuffix (это Т HexNumber), где Т: IFormattable'? – stuartd

+1

Возможно, вы разместите это на [Code Review] (http://codereview.stackexchange.com/), так как не кажется, что вы просите о помощи в решении проблемы, как таковой. –

+1

В вашем текущем решении будет введен тип box и value, в котором можно избежать дженериков. Как бы то ни было, что произойдет, если вы передадите объект, где шестнадцатеричный формат не имеет смысла? Ни дженерики, ни ваше текущее решение не защитят вас от этого. – InBetween

ответ

1

Здесь вы можете использовать общие параметры и параметры интерфейса, чтобы всегда предлагать лучшую производительность (избегайте бокса) и сохраняйте свой код DRY.

Давайте начнем с нашего общего кода.

private static string appendHexSuffix(this string hexString) 
    if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture) 
     && 
     !hexString.EndsWith("h", true, CultureInfo.InvariantCulture)) 
    { 
     hexString += "h"; 
    } 
    return hexString; 
} 

Далее позволяет обеспечить две перегрузки. Во-первых, один для IFormattable.

public static string AppendHexSuffix(this IFormattable hexNumber) => 
    appendHexSuffix(hexNumber.ToString(null, CultureInfo.InvariantCulture)); 

Теперь наш общий, когда этот метод подписи не соответствует тому, что мы проходим в.

public static string AppendHexSuffix<T>(this T hexNumber) => 
    appendHexSuffix(hexNumber.ToString()); 

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

Немного не по теме, но я спрашиваю, действительно ли вы хотите, чтобы этот метод вообще принимал какой-либо объект. Возможно, вам будет лучше с общим ограничением, определяющим каждый тип, который вы хотите принять. Или, может быть, интерфейс.Читайте об общих ограничениях здесь: https://msdn.microsoft.com/en-us/library/d5x73970.aspx

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

public static string AppendHexSuffix<T>(this T hexNumber) 
{ 
    var hexString = (hexNumber as IFormattable)? 
     .ToString(null, CultureInfo.InvariantCulture) ?? hexNumber.ToString(); 
    if (!hexString.StartsWith("0x", true, CultureInfo.InvariantCulture) 
     && !hexString.EndsWith("h", true, CultureInfo.InvariantCulture)) 
    { 
     hexString += "h"; // Append hex notation suffix, if missing prefix/suffix 
    } 
    return hexString; 
} 
+0

Интересное предложение. Хотя перегрузки все еще необходимы, по крайней мере, их осталось только 2. –

+0

Перегрузки не требуются, так как с помощью generic вы можете использовать hexNumber is/as IFormattable, а затем удалить закрытый метод. Тем не менее, я предпочитаю подход перегрузки, поскольку он удаляет проверку/листинг типа из вашего кода. – Licht

+0

Было бы общим подходом _without overloads_, лучшим вариантом, чем объектный подход? –

1

Я думаю, вам может быть полезно использовать регулярные выражения для чего-то подобного.

Во-первых, Convert.ToString уже будет форматировать объект так, как вам нужно, чтобы вы могли заменить этот код.

Чтобы преобразовать значение в его строковое представление, метод пытается выполнить , вызывая реализацию значения IConvertible.ToString. Если значение не реализует интерфейс IConvertible, метод пытается вызвать реализацию значения IFormattable.ToString. Если значение не реализует интерфейс IFormattable, метод вызывает метод ToString базового типа значения.

Во-вторых, если вам нужна строка, чтобы выглядеть определенным образом, регулярные выражения - это почти всегда путь. Они тоже очень быстры, если вы их скомпилируете. 99% времени, когда вы хотите поместить объект регулярного выражения в статическую переменную по этой причине. Я использую Regexr для проверки регулярных выражений. Он имеет дополнительное преимущество изящно, за исключением случаев, когда возвращаемая строка определенно не является шестнадцатеричной.

private static Regex _parser = new Regex(@"(0x)?((\d{2})+)h?", RegexOptions.Compiled); 
public static string AppendHexSuffix(this object hexNumber) 
{ 
    var hexString = Convert.ToString(hexNumber); 
    var match = _parser.Match(hexString); 
    if (!match.Success) 
    throw new FormatException("Object cannot be converted to a hex format"); 
    return match.Groups[2].Value + "h"; 
} 

#if DEBUG 
public static void AppendHexSuffixTest() 
{ 
    AppendHexSuffixTest("0x121212", "121212h"); 
    AppendHexSuffixTest("0x121212h", "121212h"); 
    AppendHexSuffixTest("121212h", "121212h"); 
} 

public static void AppendHexSuffixTest(object test, string expected) 
{ 
    if (test.AppendHexSuffix() != expected) 
    throw new Exception("Unit test failed"); 
} 
#endif 
+0

Хорошая альтернатива! Благодаря! –

 Смежные вопросы

  • Нет связанных вопросов^_^