导致方法签名解析不明确的隐式运算符

implicit operator causing ambiguous method signature resolution

提问人:MonkeyFace 提问时间:10/22/2023 最后编辑:MonkeyFace 更新时间:10/23/2023 访问量:76

问:

我有以下两种方法,它们都为我创建了几个实例。第一个创建类型,第二个创建以下类型:Constraint<T>Constraint<Quantity>Constraint<IParameter<Quantity>>

public void ConstrainBetween(Quantity min, Quantity max)
{
  .. 
}

public void ConstrainBetween(IParameter<Quantity> min, IParameter<Quantity> max)
{
  .. 
}

参数类型如下:QuantityIParameter<T>

public class Quantity
{
  double Value;
  .. 
}

public class IParameter<T> 
{
  T Value;
  Func<T> Formula;
  .. 
}

几个月来,一切都运行良好,直到我重载了 IParameter 的隐式运算符,如下所示:

public class IParameter<T>
{
     public T Value;
     public Func<T> Formula;
  

     public static implicit operator T(IParameter<T> p)
     {
         return p.Value; 
     }
}

现在,不再编译以下用法:

HydrModel.TopWaterLevel5yr.ConstrainBetween(OutletPipe.IL, Transform.Z);
HydrModel.TopWaterLevel30yr.ConstrainBetween(OutletPipe.IL, Transform.Z);

错误:

以下方法或属性之间的调用不明确:“QuantityInput.ConstrainBetween(Quantity, Quantity)”和“QuantityInput.ConstrainBetween(IParameter, IParameter)”

我知道编译器隐式转换为使两个方法签名都成为潜在目标,并且我知道我可以通过以下方式解决歧义问题:IParameter<Quantity>Quantity

  1. 不重载隐式运算符
  2. 改用显式运算符重载
  3. 使用两个不同的方法名称

我不想 1 或 2,因为隐式重载在其他地方的好处超过了这个缺点。

我目前打算采取策略 (3) 并使用不同的签名名称。

我发布这个问题只是为了以防万一有另一种方法可以让我吃蛋糕?例如,有没有办法在调用中准确指定方法签名以调用它?

编辑

有人问我为什么需要这两种方法 - 为什么不直接摆脱第二种方法,因为隐式重载将确保调用第一种方法?
原因是调用始终返回相同的 Quantity,而调用根据其 Formula 属性在不同的时间返回不同的 Quantity。因此,我确实需要一个策略来创建一个约束,其中 T 可以是 T 或 。
Constraint<Quantity>.ValueConstraint<IParameter<Quantity>>.ValueQuantityIParameter<Quantity>

C# 隐式转换 ambiguous-call

评论


答:

4赞 AgentFire 10/22/2023 #1

如果 u 被正确设计为隐式强制转换为 ,那么在第二种方法 ConstrainBetween 中就不需要任何了。似乎也只是一个简单的 DTO,携带一个值,而不是其他任何东西。IParameter<Quantity>QuantityIParameter

因此,我的解决方案是完全摆脱并专注于第一种方法中的值,而不是值的携带类型。public void ConstrainBetween(IParameter<Quantity> min, IParameter<Quantity> max)

更新

由于@MonkeyFace编辑了他的帖子,我还想补充一些想法。

现在似乎不再带有单个值,而是两个或多个值。更新的问题中描述的两种方法之间的差异也表明,这与它的值并不等价。IParameter<T>IPerameter<T>T

从这个角度来看,现在有一个运算符似乎很奇怪,因为 (a) 它丢失了额外的信息(因为丢失信息应该只是故意这样做 - 在我看来)和 (b) 这两种类型彼此不等价。implicit

因此,新提议的更改是从隐式操作器迁移到显式操作器

我看到你的评论说“使用显式操作器有缺点”,但我认为这些缺点是必须在那些应该发生演员的场景中使用,我认为这些情况是较小的邪恶。(T)

评论

1赞 MonkeyFace 10/22/2023
对不起,我完全理解这种混淆,所以我将编辑我的帖子以尝试解释。感谢您阅读并回答我的问题。
0赞 AgentFire 10/23/2023
@MonkeyFace好的,我已经更新了我的帖子。
0赞 MonkeyFace 10/23/2023
谢谢 - 我会将您的回复标记为理想的答案,即使我实际上(目前)不会出于对项目深奥的原因这样做,但原则上我确实同意你 90% 的情况。
0赞 MonkeyFace 10/22/2023 #2

我似乎通过更改第二个签名来回答我自己的问题:

public void ConstrainBetween(IParameter<Quantity> min, IParameter<Quantity> max)
{
}

对此:

public void ConstrainBetween<T>(T min, T max) where T : IParameter<Quantity>
{
}

我猜现在允许编译器在隐式转换之前找到标记为具有匹配类型的方法。...无论如何,该项目现在可以编译。

虽然这是我在这个特定项目上选择的解决方案,但总的来说,我同意我 90% 的项目的标记解决方案。