10

有人可以向我解释为什么这在 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()会丢失......

4

2 回答 2

15

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

奖励——如果你愿意,你可以new()对类型参数施加一个约束T,然后它甚至可以让你调用它的默认构造函数:

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();
}
于 2015-11-25T23:42:54.277 回答
0

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

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

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

因此,绝对没有从IInterfaceAto的隐式转换ImpA,而您的代码需要它。

于 2013-02-08T02:29:09.753 回答