通过ref传递实现:无法从'Foo'转换为'ref IFoo'

JHo*_*wIX 10 c# interface reference argument-passing

有人可以向我解释为什么在C#中这是不正确的:

namespace NamespaceA
{
    public class ClassA
    {
        public interface IInterfaceA
        {
            String Property
            {
                set;
            }
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class ImpA: NamespaceA.ClassA.IInterfaceA
        {
            private String mProperty;
            public String Property{ set{ mProperty = value; } }
        }
        public ClassB()
        {
            ImpA aImpA = new ImpA();
            foo(ref aImpA);
        }

        private void foo(ref NamespaceA.ClassA.IInterfaceA aIInterfaceA)
        {
            aIInterfaceA.Property = "SomeValue";
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这将产生一个编译错误:

错误参数1:无法从'NamespaceB.ClassB.ImpA'转换为'ref NamespaceA.ClassA.IInterfaceA'

想要修改接口属性并调用接口函数似乎是完全合理的foo().如果您删除ref关键字,它会进行编译,但您所做的更改foo()会丢失...

Sai*_*ali 13

作为KARTHIK说,refout不支持面向对象的多态性.但是您可以使用泛型(也称为参数多态)来实现相同的效果.

尝试将签名更改foo为:

private void foo<T>(ref T aIInterfaceA) 
    where T : NamespaceA.ClassA.IInterfaceA
{
    aIInterfaceA.Property = "SomeValue";

    // This assignment will be visible to the caller of foo
    aIInterfaceA = default(T);
}
Run Code Online (Sandbox Code Playgroud)


hor*_*rgh 0

首先,那里不需要使用关键字ref

您将引用类型的实例作为参数传递,并且不需要将参数标记为ref能够修改其状态(此处为Property属性)。只需删除ref关键字,它就会按预期工作。

其次,再想一想。一旦接口的实例是引用类型,ref参数就可以更改传递的引用,因此理论上您可以返回该接口的完全不同的实现。

因此,肯定不存在从IInterfaceAto 的隐式转换ImpA,而您的代码需要这样的转换。