簡體   English   中英

C#僅通過接口訪問類型為泛型參數類型的泛型類成員

[英]C# Access to a generic class member whose type is a generic argument type, only via an interface

我有一個泛型類,它擁有一個類型為參數類型的成員。
我希望只能通過其實現的接口之一訪問此成員。
我只想通過這個接口訪問成員,而不是枚舉它可能的所有具體類型的原因是因為有很多這些類型。

具體來說,我想在該代碼中找到等效的第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();
                    }
                }
            }
        }
}
}

注意:您可以在此處分叉和編輯代碼。

您收到編譯錯誤,因為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年對代碼進行了測試,但它確實有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM