通过ref传递实现:无法从';Foo';到';参考IFoo';

本文关键字:Foo IFoo 参考 ref 实现 通过 | 更新日期: 2023-09-27 17:58:20

有人能向我解释为什么这在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()中所做的更改将丢失。。。

通过ref传递实现:无法从';Foo';到';参考IFoo';

正如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);
}

Bonus-如果您愿意,您可以在类型参数T上设置new()约束,然后它甚至允许您调用其默认构造函数:

private void foo<T>(ref T aIInterfaceA) 
    where T : NamespaceA.ClassA.IInterfaceA, new()
{
    aIInterfaceA.Property = "SomeValue";
    // This assignment will be visible to the caller of foo
    aIInterfaceA = new T();
}

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

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

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

因此,毫无疑问,从IInterfaceAImpA没有隐式转换,而您的代码需要一个。

相关文章: