bthulu
V2EX  ›  C#

定义了一个泛型类, 有什么办法能将一个泛型类实例赋值给未指定泛型的泛型类吗? 类似 Java 里的 List = new ArrayList<String>()

  •  
  •   bthulu · May 20, 2022 · 2296 views
    This topic created in 1477 days ago, the information mentioned may be changed or developed.

    C#自身是通过定义两个同名但不同命名空间的类来解决的, 这可能是历史遗留问题导致的.

    System.Collections.IList list = new List<int>();
    
    System.Collections.Generic.IList<int> list = new List<int>();
    
    

    如果我自己有这么个类 Singer<T>, 有一个实例是反射创建的, 要把这个实例赋值给 Singer, 这要怎么处理呢?

    var instance = Activator.CreateInstance(...);
    // 下面这句怎么写? 这里确实可以通过反射拿到 instance 的具体类型, 但是代码里如何才能赋值给一个 Singer?
    // java 里可以用?或者 object 代替, 但是 C#里就直接报错了
    Singer<?> singer = instance;
    
    12 replies    2022-08-07 23:57:58 +08:00
    hez2010
        1
    hez2010  
       May 20, 2022 via Android
    不是的,C# 里面非泛型的集合类接口和类型是已经淘汰的类型,一般不会使用。
    zgcwkj
        2
    zgcwkj  
       May 22, 2022
    不知道我理解对不对,可以试试 CopyTo 或者 Linq 赋值
    INCerry
        3
    INCerry  
       May 22, 2022
    如果我理解没错,那你直接强转就可以了呀
    ```C#
    var obj = Activator.CreateInstance(typeof(List<int>));
    List<int> intList = (List<int>)obj;
    Console.WriteLine(intList.Count);
    ``
    bthulu
        4
    bthulu  
    OP
       May 23, 2022
    @INCerry 强转你得知道确切的类型啊,我都知道确切的类型了, 我还反射创建实例干嘛,我直接 new 不好么?
    问题就出在这个类型事先是不知道的,是通过 json 配置文件里的注册信息匹配到类的 Type ,你仅仅知道类的 Type , 这个 type 也是通过 Assemble 遍历所有的类,将其中实现了某个接口的类的类型注册到注册器中。就像下面这样, 你怎么个强转法?
    ```
    static Dictionary<string, Type> registers = new();

    Type type = registers["key"];
    var obj = Activator.CreateInstance(type);
    ```
    INCerry
        5
    INCerry  
       May 23, 2022
    @bthulu 那你题目里面的例子举的不是很好,简单的方案你可以直接用 dynamic 或者上面你提到的直接用 IList 。复杂的方案代码生成(表达式树、Emit )
    ```
    var obj = Activator.CreateInstance(typeof(List<int>));
    dynamic intList = obj;
    Console.WriteLine(intList.Count);
    intList.Add(1);
    Console.WriteLine(intList[0]);
    // output :
    // 0
    // 1
    ```
    INCerry
        6
    INCerry  
       May 23, 2022
    @INCerry 还有 Roslyn 动态编译,类似 natasha 那样
    SMGdcAt4kPPQ
        7
    SMGdcAt4kPPQ  
       May 23, 2022 via Android   ❤️ 1
    让 Singer<T>继承 Singer 即可
    forgottencoast
        8
    forgottencoast  
       Jun 2, 2022
    @ComputerIdiot
    一般都是这样处理,也符合 OO 。
    Aloento
        9
    Aloento  
       Jul 22, 2022
    bthulu
        10
    bthulu  
    OP
       Jul 23, 2022
    @Aloento 继承不行的. Singer<T>里可以定义方法 Add(T t), Singer 里可就没法这样定义了.
    Singer<T>继承 Singer, 将 Singer<T>实例赋值给 Singer, 那就没法调用 Add 方法了, 只能转换成 dynamic 去调了
    Aloento
        11
    Aloento  
       Jul 24, 2022
    那只能考虑一下 dynamic 了,还好,dynamic 只是初次调用的时间稍微长一点点,再次调用就没什么区别
    hez2010
        12
    hez2010  
       Aug 7, 2022 via Android
    interface ISinger
    {
    void Add(object t);
    }

    interface ISinger<T> : ISinger
    {
    void Add(T t);
    }

    class Singer<T> : ISinger<T>
    {
    public void Add(T t) { ... }

    // 这里显式实现接口确保该方法不会直接公开暴露在 Singer<T> 的成员中
    void ISinger.Add(object t) { Add((T)t); }
    }

    试试这样呢?
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   3875 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 39ms · UTC 00:09 · PVG 08:09 · LAX 17:09 · JFK 20:09
    ♥ Do have faith in what you're doing.