2

我将尝试通过一个示例来解释我的问题:

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. 我必须明确指定<string>方法的通用参数DoSomething
  2. 在这里,我必须添加显式强制转换(V<string>),隐式运算符似乎不起作用。

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

4

3 回答 3

5

你的第二个问题是为什么隐式转换从()=>""toV<string>不成功,即使()=>""is convertible toFunc<string>并且Func<string>is convertible to V<string>

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

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

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

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

于 2013-01-02T01:40:10.097 回答
3

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

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

DoSomething("");

不推断该呼叫的目的是

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

正确的?

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

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

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

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

从to没有标准的隐式转换。那是用户定义的隐式转换。stringV<string>

因此类型推断失败。

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

于 2013-01-02T01:27:53.607 回答
0

我知道您的问题是“为什么类型推断不起作用”,但我只是想我会在最后解决您关于 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"));
}
于 2013-01-02T04:50:49.287 回答