C#仅通过接口访问类型为泛型参数类型的泛型类成员

时间:2013-12-18 09:35:54

标签: c# generics interface member

我有一个泛型类,它拥有一个类型为参数类型的成员 我希望只能通过它实现的接口之一访问该成员 我只想通过这个接口访问成员,而不是枚举它可能的所有具体类型的原因是因为有很多这些类型。

具体而言,我想在该代码中找到等效的第61行(这是编译错误):

using System;
using System.Linq;

/* Interfaces */
public interface IArgumentClass
{
    void IArgumentClassMethod();
}
public interface ISpecialArgumentClass
{
    void ISpecialArgumentClassMethod();
}
public interface IContainerClass
{
    void IContainerClassClassMethod();
}

/* Argument types */
public class ArgumentClass0 : IArgumentClass
{
    public void IArgumentClassMethod(){}
}
public class SpecialArgumentClass0 : IArgumentClass, ISpecialArgumentClass
{
    public void IArgumentClassMethod(){}
    public void ISpecialArgumentClassMethod(){}
}
public class SpecialArgumentClass1 : IArgumentClass, ISpecialArgumentClass
{
    public void IArgumentClassMethod() { }
    public void ISpecialArgumentClassMethod() { }
}

/* Container types */
public class GenericContainer<T> : IContainerClass
    where T : IArgumentClass, new()
{
    public T t = new T();
    public void IContainerClassClassMethod() { }
}
public class NonGenericContainer : IContainerClass
{
    public void IContainerClassClassMethod(){}
}

/* main program */
public class Test
{
    public static void Main()
    {
        // Instantiate
        IContainerClass[] containers = 
        {
            new GenericContainer<ArgumentClass0>(),
            new GenericContainer<SpecialArgumentClass0>(),
            new GenericContainer<SpecialArgumentClass1>(),
            new NonGenericContainer()
        };

        // We want to call IContainerClassClassMethod methods on all instances:
        foreach (IContainerClass container in containers)
            container.IContainerClassClassMethod();

        // We want to call ISpecialArgumentClassMethod on instances where it's possible:
        foreach (IContainerClass container in containers)
        {
            if (container.GetType().IsGenericType && container.GetType().GetGenericTypeDefinition() == typeof(GenericContainer<>))
            {
                foreach (Type typeArgument in container.GetType().GetGenericArguments())
                {
                    if (typeArgument.GetInterfaces().Contains(typeof(ISpecialArgumentClass)))
                    {
                        // Next line is a compilation error. How can I get a similar result?
                        GenericContainer<ISpecialArgumentClass> mySpecializedClassWithSpecialArgument = container as GenericContainer<ISpecialArgumentClass>;
                        mySpecializedClassWithSpecialArgument.t.ISpecialArgumentClassMethod();
                    }
                }
            }
        }
}
}

注意:您可以分叉和编辑代码here

2 个答案:

答案 0 :(得分:2)

您收到编译错误,因为ISpecialArgumentClass不是IArgumentClass类型,但您的GenericClass要求完全相同。

要解决这个问题,您可以引入一个空接口,作为两个参数类的基础:

首先,修改你的界面声明:

public interface IArgumentClassBase
{
}

public interface IArgumentClass : IArgumentClassBase
{
    String GetNormalString();
}

public interface ISpecialArgumentClass : IArgumentClassBase
{
    String GetSpecialString();
}

...然后像这样修改你的泛型类声明:

public class GenericClass<T> : IContainerClass
    where T : IArgumentClassBase, new()

然后你的其余代码应该有用......

答案 1 :(得分:1)

一个非常简单的解决方案就是将其转换为动态 - 你知道它有一个t字段,所以这应该是安全的。

if (typeArgument.GetInterfaces().Contains(typeof(ISpecialArgumentClass)))
{
    dynamic mySpecializedClassWithSpecialArgument =
        mySpecializedClass as dynamic;

    ISpecialArgumentClass specialArgumentClass = mySpecializedClassWithSpecialArgument.t;

    Console.WriteLine(specialArgumentClass.GetSpecialString());
}

注意

我尝试在ideone中编辑它,但它无法编译。我怀疑它的目标是.NET的旧版本 - 动态是在.NET 4(VS 2010)中引入的。但是,我已经在2013年对代码进行了测试,但它确实有效。