C# 重载解析中未考虑隐式转换?

C# 重载解析中未考虑隐式转换?,c#,implicit-conversion,overload-resolution,C#,Implicit Conversion,Overload Resolution,我正在尝试包装一个类型(在我的控制之外),以便它能够无缝地实现一个接口(也在我的控制之外) 鉴于这些定义 // External types. Not changable. class Foo { public int I { get; set; } public int J { get; set; } } interface IGenerateSignature { string Generate(); } 我想使用Foo实例调用带有IGenerateSignatur

我正在尝试包装一个类型(在我的控制之外),以便它能够无缝地实现一个接口(也在我的控制之外)

鉴于这些定义

// External types. Not changable.
class Foo {
    public int I { get; set; }
    public int J { get; set; }
}
interface IGenerateSignature {
    string Generate();
}
我想使用
Foo
实例调用带有
IGenerateSignature
参数的方法:

void Test() {
    var foo = new Foo { I = 1, J = 2 };
    GetSignature(foo);
}

void GetSignature(IGenerateSignature sig) {
    Console.Write(sig.Generate());
}
我尝试创建一个中间结构,如下所示:

struct FooSignaturizer : IGenerateSignature {
    private readonly Foo _foo;
    public FooSignaturizer(Foo f) {
        _foo = f;
    }
    public static implicit operator FooSignaturizer(Foo f) {
        return new FooSignaturizer(f);
    }
    public string Generate() {
        return _foo.I + ":" + _foo.J;
    }
}
但是由于某种原因,重载解析无法找到从
Foo
foosignatureizer
的转换,我得到了一个“cannotconvert”编译器错误。如果我手动添加一个cast,
GetSignature((foosignatureizer)foo)
,它会工作。但是,我还需要添加对
Bar
Qux
类型的支持,使用
barSignatureizer
quxsignatureizer
,因此强制转换将不适用于这些情况

有没有办法做到这一点

根据C#spec的7.5.3.1,只考虑从参数表达式到参数类型的隐式转换

7.5.3.1适用的职能成员

当以下所有条件均为真时,函数成员被称为参数列表A的适用函数成员

  • A
    中的每个参数都对应于§7.5.1.1中所述的函数成员声明中的一个参数,任何参数都不对应于可选参数
  • 对于
    A
    中的每个参数,参数的参数传递模式(即值、
    ref
    out
    )与相应参数的参数传递模式相同,并且
    • 对于值参数或参数数组,存在从参数到相应参数类型的隐式转换(§6.1),或
    • 对于
      ref
      out
      参数,参数的类型与相应参数的类型相同。毕竟,
      ref
      out
      参数是所传递参数的别名
这里的不是从
Foo
IGenereateSignature
的隐式转换,而是一个包装器

作为对这种行为的解释,您不能执行编译器来检查范围内
IGenerateSignature
的每个实现,以查看它是否有到
Foo
的隐式转换。如果不止一个呢


关于如何为
Foo
Bar
Qux
实现这一点

您试图实现的,一次调用
GetSignature(foorBarorqux)
,是不可能的,因为(根据您对
Foo
的描述)在编译时不能有一个变量可以是
Foo
Bar
Qux
,它们是不相关的。您总是需要三个调用站点,因此对于这三种情况,没有理由不进行三种稍微不同的转换(包装类或重载方法调用等)

。。。除非根据C#spec的7.5.3.1使用
动态

,否则只考虑从参数表达式到参数类型的隐式转换

7.5.3.1适用的职能成员

当以下所有条件均为真时,函数成员被称为参数列表A的适用函数成员

  • A
    中的每个参数都对应于§7.5.1.1中所述的函数成员声明中的一个参数,任何参数都不对应于可选参数
  • 对于
    A
    中的每个参数,参数的参数传递模式(即值、
    ref
    out
    )与相应参数的参数传递模式相同,并且
    • 对于值参数或参数数组,存在从参数到相应参数类型的隐式转换(§6.1),或
    • 对于
      ref
      out
      参数,参数的类型与相应参数的类型相同。毕竟,
      ref
      out
      参数是所传递参数的别名
这里的不是从
Foo
IGenereateSignature
的隐式转换,而是一个包装器

作为对这种行为的解释,您不能执行编译器来检查范围内
IGenerateSignature
的每个实现,以查看它是否有到
Foo
的隐式转换。如果不止一个呢


关于如何为
Foo
Bar
Qux
实现这一点

您试图实现的,一次调用
GetSignature(foorBarorqux)
,是不可能的,因为(根据您对
Foo
的描述)在编译时不能有一个变量可以是
Foo
Bar
Qux
,它们是不相关的。您总是需要三个调用站点,因此对于这三种情况,没有理由不进行三种稍微不同的转换(包装类或重载方法调用等)


。。。除非你们使用
dynamic

罗琳的回答很好地解释了你们为什么会遇到问题。关于如何实现你想要的。我可能会考虑这样的事情:

public interface ISignaturizer
{
    IGenerateSignature ToSignaturizer();
}

struct FooSignaturizer : IGenerateSignature, ISignaturizer{
    private readonly Foo _foo;
    public FooSignaturizer(Foo f) {
        _foo = f;
    }

    public string Generate() {
        return _foo.I + ":" + _foo.J;
    }

    public IGenerateSignature ToSignaturizer()
    {
        return (IGenerateSignature)this;
    }
}
void Test() {
    var foo = new Foo { I = 1, J = 2 };
    GetSignature(foo.AsIGenerateSignature());
}

void GetSignature(IGenerateSignature sig) {
    Console.Write(sig.Generate());
}

public static class GenerateSignatureExtensions
{
    public static IGenerateSignature AsIGenerateSignature(this IGenerateSignature me)
    {
        return me;
    }
    public static IGenerateSignature AsIGenerateSignature(this Foo me)
    {
        return new FooSignaturizer(me);
    }
    public static IGenerateSignature AsIGenerateSignature(this Bar me)
    {
        return new BarSignaturizer(me);
    }
    //....
现在,
barSignatureizer
qxsignatureizer
可以实现相同的接口。然后你可以做:

GetSignature(((ISignaturizer)fooOrBarOrQux).ToSignaturizer());

这并没有那个么优雅,但我认为应该可以满足你们的需要。

罗琳的回答很好地解释了你们为什么会有问题。关于如何实现你想要的。我可能会考虑这样的事情:

public interface ISignaturizer
{
    IGenerateSignature ToSignaturizer();
}

struct FooSignaturizer : IGenerateSignature, ISignaturizer{
    private readonly Foo _foo;
    public FooSignaturizer(Foo f) {
        _foo = f;
    }

    public string Generate() {
        return _foo.I + ":" + _foo.J;
    }

    public IGenerateSignature ToSignaturizer()
    {
        return (IGenerateSignature)this;
    }
}
void Test() {
    var foo = new Foo { I = 1, J = 2 };
    GetSignature(foo.AsIGenerateSignature());
}

void GetSignature(IGenerateSignature sig) {
    Console.Write(sig.Generate());
}

public static class GenerateSignatureExtensions
{
    public static IGenerateSignature AsIGenerateSignature(this IGenerateSignature me)
    {
        return me;
    }
    public static IGenerateSignature AsIGenerateSignature(this Foo me)
    {
        return new FooSignaturizer(me);
    }
    public static IGenerateSignature AsIGenerateSignature(this Bar me)
    {
        return new BarSignaturizer(me);
    }
    //....
现在
barSignatureizer
qxsig