如何避免多个参数类型的方法重载(除了使用对象参数)?

How to avoid method overloads for multiple parameter types (else than by using object parameter)?

我正在寻找一种方法,在 1) 总是将参数转换为字符串且 2)[= 的情况下如何避免冗长的重载38=] 应该可用于将其他类型作为参数传递。

一如既往一张图片片段值一千字并找到了以下解决方案。示例:(即通过使用对象参数,is cast to IFormattable for 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 语句部分只有在 [=47= 的情况下才有意义] 字符串作为参数传递。


编辑: 在考虑了我得到的答案和评论之后,经过更多的试验,以下最终实现似乎最适合我的情况:

/// <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;
}

由此,它也应该忽略 parameters/objects 十六进制格式没有意义的地方,正如@InBetween 的评论中指出的那样。值得注意的错误:忘记了第一个 .ToString() 调用的 "X" 格式。

您可以在此处使用泛型和接口参数来始终获得最佳性能(避免装箱)并保持代码干爽。

让我们从常用代码开始。

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());

由于 T 可以隐含,我们不需要指定它,就假装根本没有泛型。

有点题外话,但我想知道您是否真的希望此方法接受任何类型的对象。您最好使用一个通用约束来指定您想要接受的每种类型。或者也许是一个接口。在此处阅读有关通用约束的信息: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;
}

我认为你最好使用正则表达式来处理这样的事情。

首先,Convert.ToString 已经按照您需要的方式格式化对象,因此您可以替换该代码。

To convert value to its string representation, the method tries to call the IConvertible.ToString implementation of value. If value does not implement the IConvertible interface, the method tries to call the IFormattable.ToString implementation of value. If value does not implement the IFormattable interface, the method calls the ToString method of the underlying type of value.

其次,当您需要一个字符串以某种方式显示时,正则表达式几乎总是可行的方法。如果你编译它们,它们也非常快。出于这个原因,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