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的适用函数成员:
中的每个参数都对应于§7.5.1.1中所述的函数成员声明中的一个参数,任何参数都不对应于可选参数A
- 对于
中的每个参数,参数的参数传递模式(即值、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的适用函数成员:
中的每个参数都对应于§7.5.1.1中所述的函数成员声明中的一个参数,任何参数都不对应于可选参数A
- 对于
中的每个参数,参数的参数传递模式(即值、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