含隐式转换的超载分辨率 [英] Overload Resolution with implicit conversions

查看:69
本文介绍了含隐式转换的超载分辨率的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我基本上希望为string/FormattableString提供两个单独的重载(背景是我希望促使人们倾向于将字符串常量用于日志消息,并通过结构化日志而不是日志消息来传递参数,以简化分析.因此,FormattableString日志记录方法将被淘汰).

I basically want two separate overloads for string/FormattableString (the background is that I want to nudge people towards using string constants for log messages and pass parameters via structured logging instead of the log message to simplify analysis. So the FormattableString logging method would be obsoleted).

现在由于编译器的工作方式,您不能直接重载方法,因为FormattableString在传递之前会降级为字符串.不过,有效的方法是拥有一个定义隐式重载的包装器结构:

Now due to the way the compiler works, you cannot directly overload the methods, because a FormattableString devolves to a string before it's being passed. What does work though is to have a wrapper struct that defines implicit overloads:

public struct StringIfNotFormattableStringAdapter
{
    public string StringValue { get; }

    private StringIfNotFormattableStringAdapter(string s)
    {
        StringValue = s;
    }

    public static implicit operator StringIfNotFormattableStringAdapter(string s)
    {
        return new StringIfNotFormattableStringAdapter(s);
    }

    public static implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)
    {
        throw new InvalidOperationException("This only exists to allow correct overload resolution. " +
                                            "This should never be called since the FormattableString overload should be preferred to this.");
    }
}

public static class Test
{
    public static void Log(StringIfNotFormattableStringAdapter msg)
    {
    }

    public static void Log(FormattableString msg)
    {
    }

    public static void Foo() 
    {
         Log("Hello"); // resolves to StringIfNotFormattableStringAdapter overload
         Log($"Hello"); // resolves to FormattableString overload 
    } 

}

到目前为止,一切都很好.

So far so good.

我不明白的地方:为什么要删除

What I don't understand: Why does removing the

implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)

是否导致调用 Log($"Hello")变得模棱两可?

cause the call Log($"Hello") to become ambiguous?

CS0121下列方法或属性之间的调用不明确:Test.Log(StringIfNotFormattableStringAdapter)'和'Test.Log(FormattableString)'`

CS0121 The call is ambiguous between the following methods or properties: Test.Log(StringIfNotFormattableStringAdapter)' and 'Test.Log(FormattableString)'`

推荐答案

根据C#规范,

According to C# Specification, Interpolated strings, there is an implicit conversion from interpolated string to FormattableString:

interpolated_string_expression 被归类为一个值.如果是立即转换为 System.IFormattable System.FormattableString (带有隐式插值字符串)转换(隐含插值字符串转换),插值字符串表达式具有该类型.否则,它具有键入 string .

An interpolated_string_expression is classified as a value. If it is immediately converted to System.IFormattable or System.FormattableString with an implicit interpolated string conversion (Implicit interpolated string conversions), the interpolated string expression has that type. Otherwise, it has the type string.

在提供的代码中,还将 string 转换为 StringIfNotFormattableStringAdapter .

In the provided code there is also conversion of string to StringIfNotFormattableStringAdapter.

方法调用

Log($"Hello");

可以解析为两个 Log 方法,因为插值字符串表达式 $"Hello" 可以是:

can be resolved to both Log methods, because interpolated string expression $"Hello" can be:

  • 作为插值字符串隐式转换为 FormattableString
  • 作为 string 隐式转换为 StringIfNotFormattableStringAdapter .
  • implicitly converted to FormattableString as interpolated string;
  • implicitly converted to StringIfNotFormattableStringAdapter as string.

在这里,编译器会出现歧义,并且需要其他规则来解决这种歧义.要解决歧义性编译器,请使用C#规范中所述的规则,

Here an ambiquity occurs to compiler and it needs additional rules to resolve this ambiguity. To resolve the ambiguity compiler uses rules that are described in C# Specification, Better Conversion Target (go to the bottom of the page 164). The rules say that:

给出两种不同的类型 T1 T2 T1 是更好的转换如果不存在从 T2 T1 的隐式转换,则目标为 T2 ,并至少满足以下条件之一:

Given two different types T1 and T2 , T1 is a better conversion target than T2 if no implicit conversion from T2 to T1 exists, and at least one of the following holds:

  • 存在从 T1 T2 的隐式转换

(其他规则对我们的情况并不重要)

(other rules are not important for our case)

在提供的代码中, FormattableString StringIfNotFormattableStringAdapter 更好,因为

In the provided code FormattableString is better conversion than StringIfNotFormattableStringAdapter because

  • 没有从 StringIfNotFormattableStringAdapter FormattableString
  • 的隐式转换
  • there is no implicit conversion from StringIfNotFormattableStringAdapter to FormattableString

  • 存在从 FormattableString StringIfNotFormattableStringAdapter 的隐式转换.
  • an implicit conversion from FormattableString to StringIfNotFormattableStringAdapter exists.

因此,编译器倾向于将插值字符串 $"Hello" 转换为 FormattableString ,然后调用方法 Log(FormattableString).

Therefore compiler prefers to convert interpolated string $"Hello" to FormattableString and then invokes method Log(FormattableString).

为什么要删除

implicit operator StringIfNotFormattableStringAdapter(FormattableString fs)

是否使调用 Log($"Hello")变得模棱两可?

cause the call Log($"Hello") to become ambiguous?

因为删除该运算符,第二条规则(存在从 FormattableString StringIfNotFormattableStringAdapter 的隐式转换")现在编译器无法定义更好的转换目标.这会导致编译器含糊不清,并且会发生编译错误.

Because when you remove this operator the second rule ("an implicit conversion from FormattableString to StringIfNotFormattableStringAdapter exists") breaks and now compiler cannot define better conversion target. This causes an ambiguity to compiler and compilation error occurs.

这篇关于含隐式转换的超载分辨率的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆