【问题标题】:Why type inference and implicit operator is not working in the following situations?为什么类型推断和隐式运算符在以下情况下不起作用?
【发布时间】:2012-12-16 09:46:49
【问题描述】:

我会试着用一个例子来解释我的问题:

class V<T>
{
    public readonly Func<T> Get;
    public readonly bool IsConstant;

    V(Func<T> get, bool isConstant)
    {
        Get = get;
        IsConstant = isConstant;
    }

    public static implicit operator V<T>(T value)
    {
        return new V<T>(() => value, true);
    }

    public static implicit operator V<T>(Func<T> getter)
    {
        return new V<T>(getter, false);
    }
}

void DoSomething<T>(V<T> v)
{
    //...
}

void Main()
{
    DoSomething<string>("test"); // (1) type inference is not working
    DoSomething<string>((V<string>)(() => "test")); // (2) implicit operator does not work
}

Main方法中,我有两种情况:

  1. 我必须将泛型参数 &lt;string&gt; 显式指定给方法 DoSomething
  2. 在这里,我必须添加显式转换(V&lt;string&gt;),隐式运算符似乎不起作用。

为什么需要这样做?编译器正在考虑哪些替代方案,因此无法选择正确的方式?

【问题讨论】:

  • 我的猜测:(1)编译器在知道要转换为的类型之前不会进行隐式转换,并且 是必要的。 (2) lambda 表达式没有像 Func 这样的特定委托类型,编译器看不到潜在的隐式转换。
  • (1) 好的。 (2) 你是对的,转换为 (Func) 就足够了。把它作为一个答案:)
  • Main 不调用 DoSoemthing;它调用了其他一些方法 DumpValue。

标签: c# .net generics type-inference implicit-conversion


【解决方案1】:

您的第二个问题是为什么从()=&gt;""V&lt;string&gt; 的隐式转换不成功,即使()=&gt;"" 可以转换为Func&lt;string&gt; 并且Func&lt;string&gt; 可以转换为V&lt;string&gt;

同样,我不知道如何回答“为什么不呢?”问题,但我确实知道如何回答“规范的哪一行表明编译器应该拒绝此代码?”这个问题。相关行是:

首先,如果需要,执行从源类型到用户定义或提升转换运算符的操作数类型的标准转换。

注意这里有一个小错误;这应该说是从源表达式执行标准转换。源表达式可能没有类型。我相信在我离开团队之前我已经向规范维护者提供了该说明,因此希望这将在下一版本中得到解决。

无论如何,现在应该清楚这里发生了什么。没有从 lambda 到委托类型的标准转换,因此用户定义的转换被转换解析算法归类为不适用

【讨论】:

  • Eric,也许你可以看看这个问题stackoverflow.com/q/43011140/5311735,这个问题(我认为)与这个问题有关(还涉及泛型类型推断和隐式用户定义的运算符)。这不是我的问题,但我有兴趣回答,我担心除了你之外没有人可以为这样的问题提供答案:)
【解决方案2】:

我假设您的代码打算调用 DoSomething,而不是 DumpValue。

你的问题是,首先,为什么

DoSomething("");

不推断该调用的目的是

DoSomething<string>((V<string>)"");

正确吗?

“为什么”的问题很难回答,而“为什么不呢?”问题更难。相反,我将回答一个可以回答的问题:规范的哪一行证明了这种行为?

重载解析的工作方式如下:如果方法组包含泛型方法但没有提供泛型方法类型参数,则类型推断会尝试推断类型参数。如果无法推断类型参数,则将该方法从重载决议的考虑中删除。在您的情况下,由于方法组中只有一个方法,因此删除它会导致重载解析失败。

为什么类型推断会失败? T 无法推断,因为规范的控制线是:

如果 V 是构造类型 C&lt;V1…Vk&gt; 并且存在一组唯一的类型 U1...Uk 使得存在从 U 到 C&lt;U1…Uk&gt; 的标准隐式转换,则从每个 Ui 对相应的 Vi 进行精确推断。

没有从stringV&lt;string&gt;标准隐式转换。那是用户定义的隐式转换。

因此类型推断失败。

我将在第二个答案中回答您的第二个问题。一般来说,同时提出两个问题是个坏主意。当您有两个问题时,发布两个问题。

【讨论】:

  • 对不起,“为什么”的问题:) 作为一个非常懒惰的程序员,我更喜欢 DRY。因此,如果我必须明确地说些什么,我想知道原因:)
【解决方案3】:

我知道您的问题是“为什么类型推断不起作用”,但我只是想我会在最后解决您关于 2 个替代方案的陈述。在这种情况下,我相信隐式转换的更好替代方法(我讨厌那些)是静态工厂方法。 IMO,当你调用DumpValue时语法会更好。

static class VFactory
{
    public static V<T> Create<T>(T value)
    {
        return new V<T>(() => value, true);
    }

    public static V<T> Create<T>(Func<T> getter)
    {
        return new V<T>(getter, false);
    }
}

class V<T>
{
    public readonly Func<T> Get;
    public readonly bool IsConstant;

    internal V(Func<T> get, bool isConstant)
    {
        Get = get;
        IsConstant = isConstant;
    }
}

void DumpValue<T>(V<T> v)
{
    //...
}

void Main()
{
    DumpValue(VFactory.Create("test"));
    DumpValue(VFactory.Create(() => "test"));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-08
    • 1970-01-01
    • 2015-05-26
    • 2013-10-21
    • 2023-03-18
    • 1970-01-01
    相关资源
    最近更新 更多