指定为可选Func<>的扩展方法

时间:2013-04-12 18:40:48

标签: c# extension-methods

这可能是一个相当复杂的问题,但只是检查是否有答案。

考虑有两种扩展方法大致看起来像这样(并且在另一个我无法控制的程序集中):

public static class ExtensionMethods
{
    public static string ConversionA<T>(this T self) { /* .... */ }
    public static string ConversionB<T>(this T self) { /* .... */ }
} // eo class ExtensionMethods

我有一个在对象上使用此扩展方法的方法。理想情况下,我希望调用者明确指定使用哪个转换函数,但必要时默认使用,所以我希望我可以将签名转换为Func<>

public static class Config
{
    public static T Read<T>(string fileName, Func<T, string> = ExtensionMethods.ConversionA<T>)
    {
    }
} // eo class Config

这有可能吗?我知道这是一个很长的镜头:)

2 个答案:

答案 0 :(得分:4)

  

这有可能吗?

当然 - 你无法做的唯一事情就是让Func成为可选参数。可选参数的默认值必须是编译时常量。

可以通过重载来实现:

public static T Read<T>(string fileName, Func<T, string> func) // non-optional parameter
{
    /* ... */
}

public static T Read<T>(string fileName)
{
    return Read<T>(fileName, ExtensionMethods.ConversionA<T>);
}

答案 1 :(得分:1)

修改

不幸的是我错过了你要求定义默认方法的地方。这不可能。 C#明确禁止为非编译时常量的任何内容分配默认参数。解决这个问题的唯一方法是设置一些重载方法,如下:

public static T Read<T>(T input)
{
    Read(input, ExtensionMethods.ConversionA<T>);
}

public static T Read<T>(T input, Func<T, string> conversion)
{
    // Logic goes here
}

总而言之,它并不是那么糟糕。这是一些额外的代码,它将为您提供您正在寻找的行为。

<强>原始

看起来你所拥有的应该基本上起作用。您只需指定它接受Func<T, string>即可。您无法强制始终ConversionA<T>ConversionB<T>,但这些类型签名中的任何一个都应满足Func<T, string>

例如(不知道你的转换方法做了什么,我将自己编造):

public static class Conversions
{
    public static string UpperString<T>(T self)
    {
        return self.ToString().ToUpper();
    }

    public static string LowerString<T>(T self)
    {
        return self.ToString().ToLower();
    }
}

public static T Read<T>(T input, Func<T, string> conversion)
{
    // Do-whatchya-do
}

void Main()
{
    Read<SomeObj>(new SomeObj(), Conversions.UpperString<SomeObj>);
    Read<SomeObj>(new SomeObj(), Conversions.LowerString<SomeObj>);
}

当你最终调用“Read”时,你只需要传递具有正确类型的泛型方法。因此,您可能需要稍微复制类型签名,但它应该可以正常工作。

他们是扩展方法没有任何改变。任何扩展方法都可以显式地以非扩展格式使用。例如:

public static class Extensions 
{
    public static T SomeExtension<T>(this T value) { /* ... */ }
}

可以通过以下方式在两者中调用:

someT.SomeExtension();
Extensions.SomeExtension(someT);