V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
bthulu
V2EX  ›  C#

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

  •  
  •   bthulu · 2022-05-20 15:28:31 +08:00 · 1443 次点击
    这是一个创建于 678 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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 条回复    2022-08-07 23:57:58 +08:00
    hez2010
        1
    hez2010  
       2022-05-20 22:15:40 +08:00 via Android
    不是的,C# 里面非泛型的集合类接口和类型是已经淘汰的类型,一般不会使用。
    zgcwkj
        2
    zgcwkj  
       2022-05-22 14:44:47 +08:00
    不知道我理解对不对,可以试试 CopyTo 或者 Linq 赋值
    INCerry
        3
    INCerry  
       2022-05-22 20:45:08 +08:00
    如果我理解没错,那你直接强转就可以了呀
    ```C#
    var obj = Activator.CreateInstance(typeof(List<int>));
    List<int> intList = (List<int>)obj;
    Console.WriteLine(intList.Count);
    ``
    bthulu
        4
    bthulu  
    OP
       2022-05-23 08:19:08 +08:00
    @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  
       2022-05-23 11:42:18 +08:00
    @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  
       2022-05-23 11:44:26 +08:00
    @INCerry 还有 Roslyn 动态编译,类似 natasha 那样
    SMGdcAt4kPPQ
        7
    SMGdcAt4kPPQ  
       2022-05-23 12:23:28 +08:00 via Android   ❤️ 1
    让 Singer<T>继承 Singer 即可
    forgottencoast
        8
    forgottencoast  
       2022-06-02 22:47:13 +08:00
    @ComputerIdiot
    一般都是这样处理,也符合 OO 。
    Aloento
        9
    Aloento  
       2022-07-22 20:42:41 +08:00
    bthulu
        10
    bthulu  
    OP
       2022-07-23 10:11:06 +08:00
    @Aloento 继承不行的. Singer<T>里可以定义方法 Add(T t), Singer 里可就没法这样定义了.
    Singer<T>继承 Singer, 将 Singer<T>实例赋值给 Singer, 那就没法调用 Add 方法了, 只能转换成 dynamic 去调了
    Aloento
        11
    Aloento  
       2022-07-24 01:17:18 +08:00
    那只能考虑一下 dynamic 了,还好,dynamic 只是初次调用的时间稍微长一点点,再次调用就没什么区别
    hez2010
        12
    hez2010  
       2022-08-07 23:57:58 +08:00 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); }
    }

    试试这样呢?
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5432 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 83ms · UTC 08:40 · PVG 16:40 · LAX 01:40 · JFK 04:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.