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

2022-09-17 21:00:25 +08:00
 bthulu

问题 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>();
1508 次点击
所在节点    问与答
10 条回复
hez2010
2022-09-17 21:14:19 +08:00
针对数学的泛型是在 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
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
2022-09-17 22:36:22 +08:00
@hez2010 刚才又试了下, .net core 里是没有 IComparisonOperators 这个类的, 你这个怕不是.net framework4.x 里的吧
hez2010
2022-09-17 23:04:13 +08:00
@bthulu IComparisonOperators 是 .NET 7 的
moen
2022-09-17 23:31:47 +08:00
@bthulu 具体类型是不变的,所以无法赋值。这个例子下必须使用 IReadOnlyList<Animal>
yor1g
2022-09-17 23:44:20 +08:00
这不是都用接口来约束不就行了 何必要具体类或基础类型来做约束... 都是面向对象基础
beyondex
2022-09-18 01:31:18 +08:00
1 楼正解
Magentaize
2022-09-18 08:36:45 +08:00
List 是 class 不实现协变,只有接口可以实现协变
bthulu
2022-09-18 10:09:20 +08:00
@moen 还真可以了. 可为啥不在 IList 上实现协变呢
moen
2022-09-18 16:55:12 +08:00
@bthulu IList<T> 的 T 同时出现在参数和返回值里,它就是不变的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/880881

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX