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

时间:2013-02-08 02:13:36

标签: 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";
        }
    }
}

这将产生编译错误:

  

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

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

2 个答案:

答案 0 :(得分:12)

正如Karthik所说,refout不支持面向对象的多态性。但是您可以使用泛型(a.k.a. 参数多态)来实现相同的效果。

尝试将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);
}

答案 1 :(得分:0)

首先,无需在那里使用ref关键字。

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

其次,考虑一下。只要接口的实例是引用类型,ref参数就可以更改传递的引用,因此理论上可以返回此接口的绝对不同的实现。

因此,明确地说,没有从IInterfaceAImpA的隐式强制转换,而您的代码需要一个。{/ p>