V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
bthulu
V2EX  ›  问与答

.net core 里想写一个针对所有数字类型的函数, 该怎么写, 所有类型写一遍, 还是有泛型可用? 还有.net 泛型是不是无法向上转型?

  •  
  •   bthulu · 2022-09-17 21:00:25 +08:00 · 1503 次点击
    这是一个创建于 826 天前的主题,其中的信息可能已经有所发展或是发生改变。

    问题 1:
    很简单的一个方法, 判断给点数字是不是在另两个数字范围内.

        public static bool Between(int i, int[] range)
        {
            return i >= range[0] && i <= range[1];
        }
    

    但是现在不仅仅是要判断 int, 还可能是 long, float, double.
    这种在 C#里应该怎么做? 下面这样的写法编译报错.

        public static bool Between<T>(T i, T[] range) where T: int, long, float, double
        {
            return i >= range[0] && i <= range[1];
        }
    

    问题 2: 方法里用到个链表, 需要限制链表里必须是动物, 但是可能是猫也可能是狗. 这种应该怎么写?
    下面这样的是无法通过编译的

    List<Animal> list = new List<Cat>();
    list = new new List<Dog>();
    
    10 条回复    2022-09-18 16:55:12 +08:00
    hez2010
        1
    hez2010  
       2022-09-17 21:14:19 +08:00   ❤️ 1
    针对数学的泛型是在 C# 11 才引入的,所以需要 .NET 7 ,目前发了 RC 版本。

    第一个问题:

    可以使用 `IComparisonOperators` 作为约束:

    ```csharp
    using System.Numerics;

    static bool Between<T>(T i, T[] range) where T : IComparisonOperators<T, T, bool>
    {
    return i >= range[0] && i <= range[1];
    }
    ```


    第二个问题:

    你直接用 `List<Animal> list = new List<Animal>()` 就行了,然后可以调用 `list.Add(new Dog())` 和 `list.Add(new Cat())` 往里面添加狗或者猫。

    .NET 泛型可以向上或者向下转类型,这个分别叫做协变和逆变,只能在接口上用,例如:

    ```csharp
    void Test1(IFoo1<object> s)
    {
    IFoo1<string> x = s; // ok
    }

    void Test2(IFoo2<string> s)
    {
    IFoo2<object> x = s; // ok
    }

    interface IFoo1<in T> { }
    interface IFoo2<out T> { }
    ```
    bthulu
        2
    bthulu  
    OP
       2022-09-17 22:31:10 +08:00
    @hez2010 @hez2010 第二个问题, 我这里没这么简单.
    实际是从配置文件中读取类似下面这样的
    public class Config {
    public string Farmer {get;set;}
    public List<Dog> Dogs {get;set;}
    public List<Cat> Cats {get;set;}
    }

    然后在另一个方法里动态引用 Dogs 或 Cats
    public void DoSomething(string animalType) {
    Config config = ReadFromJsonFile();

    // 这个赋值会报错, 无法将 List<Dog>或 List<Cat>赋值给 List<Animal>
    List<Animal> animals = animalType switch {
    "Dog" => config.Dogs,
    "Cat" => config.Cats,
    _ => config.Cats
    }
    foreach(var animal in animals) {
    animal.Dance();
    }
    }
    bthulu
        3
    bthulu  
    OP
       2022-09-17 22:36:22 +08:00
    @hez2010 刚才又试了下, .net core 里是没有 IComparisonOperators 这个类的, 你这个怕不是.net framework4.x 里的吧
    hez2010
        4
    hez2010  
       2022-09-17 23:04:13 +08:00
    @bthulu IComparisonOperators 是 .NET 7 的
    moen
        5
    moen  
       2022-09-17 23:31:47 +08:00
    @bthulu 具体类型是不变的,所以无法赋值。这个例子下必须使用 IReadOnlyList<Animal>
    yor1g
        6
    yor1g  
       2022-09-17 23:44:20 +08:00   ❤️ 1
    这不是都用接口来约束不就行了 何必要具体类或基础类型来做约束... 都是面向对象基础
    beyondex
        7
    beyondex  
       2022-09-18 01:31:18 +08:00 via Android
    1 楼正解
    Magentaize
        8
    Magentaize  
       2022-09-18 08:36:45 +08:00 via iPhone
    List 是 class 不实现协变,只有接口可以实现协变
    bthulu
        9
    bthulu  
    OP
       2022-09-18 10:09:20 +08:00
    @moen 还真可以了. 可为啥不在 IList 上实现协变呢
    moen
        10
    moen  
       2022-09-18 16:55:12 +08:00
    @bthulu IList<T> 的 T 同时出现在参数和返回值里,它就是不变的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2828 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 11:50 · PVG 19:50 · LAX 03:50 · JFK 06:50
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.