1

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

namespace NamespaceA
{
    public class ClassA<T1>
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output(ClassA<ICanOutput> aClassA_WithOutputCapabilities)
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}

这将导致以下编译错误:

参数 1:无法从 'NamespaceA.ClassA"<"NamespaceB.ClassB.OutputableClassA">" 转换为 NamespaceA.ClassA"<"NamespaceA.IOForClassA.ICanOutput">"

...但是 NamespaceB.ClassB.OutputableClassA 实现了 NameSpaceA.IoForClassA.ICanOutput,所以我不明白为什么这是一个问题...

我试图允许用户创建他/她希望的任何类型的 ClassA。但是,如果他们希望 ClassA “可输出”,则其模板类型必须实现特定接口。

4

3 回答 3

2

您正在解决协方差/逆变问题。基本上,只有接口可以允许泛型类型是更派生的类型,并且只有使用 in/out 关键字明确指定它们(在链接文章中概述)。

阅读您的代码,似乎您想在不知道其类型的情况下调用一个类的已知命名成员,这可能更适合类型约束。不过,您可能需要稍微更改您的设计。

namespace NamespaceA
{
    public class ClassA<T1> where T1 : IOForClassA.ICanOutput
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output<T>(ClassA<T> aClassA_WithOutputCapabilities) where T : IOForClassA.ICanOutput
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}
于 2013-02-08T04:26:10.440 回答
0

OutputableClassA源自ICanOutput。但这并不意味着ClassA<OutputableClassA>也来源于ClassA<ICanOutput>。这就是你的代码不起作用的原因。

泛型中的链接协方差和逆变可能会有所帮助。

于 2013-02-08T04:33:12.453 回答
0

@syazdani 关于它是一个协方差问题是正确的(他链接到一篇有用的文章),但他的示例没有使用协方差,这将实现您正在寻找的内容。尽管他的回答是正确的(并且可能更可取,因为它具有将实际类型带入方法中的额外好处,以防您需要将其带入Output方法中,但我想我会向您展示如何使用协变接口来执行此操作以防万一您在任何其他可能使用它们的情况下:

namespace NamespaceA
{
    public interface IClassA<out T1>
    {
        T1 Type1 { get; }
    }

    public class ClassA<T1> : IClassA<T1>
    {
        T1 mT1;
        public T1 Type1
        {
            get { return mT1; }
        }
    }

    public class IOForClassA
    {
        public interface ICanOutput
        {
            void OutputFunction();
        }

        public static void Output(IClassA<ICanOutput> aClassA_WithOutputCapabilities)
        {
            aClassA_WithOutputCapabilities.Type1.OutputFunction();
        }
    }
}

namespace NamespaceB
{
    public class ClassB
    {
        public class OutputableClassA : NamespaceA.IOForClassA.ICanOutput
        {
            public void OutputFunction()
            {
            }
        }
        public ClassB()
        {
            NamespaceA.ClassA<OutputableClassA> aOutputableA = new NamespaceA.ClassA<OutputableClassA>();
            NamespaceA.IOForClassA.Output(aOutputableA);
        }
    }
}
于 2013-02-09T05:59:36.030 回答