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

本文关键字:参数 泛型 类型 成员 泛型类 访问类型 接口 | 更新日期: 2024-10-31 18:02:12

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

所以具体地说,我想在该代码中找到与第 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();
                    }
                }
            }
        }
}
}

注意:您可以在此处分叉和编辑代码。

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

你得到编译错误,因为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()

然后你的代码的其余部分应该可以工作了...

一个非常简单的解决方案是将其转换为动态 - 你知道它有一个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 年测试了代码并且它可以工作。