c# 逆变 / 协变

个人理解:

1. 逆变in向上兼容类

2. 协变out向下兼容类

在面向对象编程中,尤其是使用泛型时,inout关键字用于限制类型参数的协变性和逆变性。

  1. in关键字(逆变):

    • in关键字用于标记泛型类型参数的逆变性。逆变表示可以使用指定类型的基类或超类作为方法的参数类型。
    • 当一个泛型类或接口使用in关键字限定类型参数时,该泛型类型可以被赋值给比它更通用的类型。
    • 例如,如果有一个只写存储库,你无法通过它查询信息,只能往里面添加动物。这种情况下,可以将泛型类型参数声明为in Animal,表示该类型参数可以是Animal或其任何基类。
  2. out关键字(协变):

    • out关键字用于标记泛型类型参数的协变性。协变表示可以使用指定类型的子类或派生类作为方法的返回类型。
    • 当一个泛型类或接口使用out关键字限定类型参数时,该泛型类型可以被赋值给比它更具体的类型。
    • 例如,如果有一个只读存储库,你无法通过它添加动物,只能查询信息。这种情况下,可以将泛型类型参数声明为out Animal,表示该类型参数可以是Animal或其任何派生类。

通过使用inout关键字,我们可以在泛型类型参数中限制类型的协变性和逆变性,以确保类型安全性。这样做的好处是能够更容易地对泛型类型进行复用和灵活性。

代码示例:

// 声明一个只读存储库接口,用于查询动物信息
interface ReadOnlyRepository<out T> {
    fun getAll(): List<T>
    fun getById(id: String): T?
}

// 声明一个只写存储库接口,用于添加动物
interface WriteOnlyRepository<in T> {
    fun add(item: T)
}

// Animal类作为基类
open class Animal(val name: String)

// Dog类继承自Animal
class Dog(name: String) : Animal(name)

// Cat类继承自Animal
class Cat(name: String) : Animal(name)

// 只读存储库实现
class ReadOnlyAnimalRepository : ReadOnlyRepository<Animal> {
    private val animals = listOf(Animal("Lion"), Dog("Buddy"), Cat("Whiskers"))

    override fun getAll(): List<Animal> {
        return animals
    }

    override fun getById(id: String): Animal? {
        return animals.find { it.name == id }
    }
}

// 只写存储库实现
class WriteOnlyAnimalRepository : WriteOnlyRepository<Animal> {
    private val animals = mutableListOf<Animal>()

    override fun add(item: Animal) {
        animals.add(item)
    }
}

fun main() {
    val readOnlyRepo: ReadOnlyRepository<Animal> = ReadOnlyAnimalRepository()
    val writeOnlyRepo: WriteOnlyRepository<Dog> = WriteOnlyAnimalRepository()

    val allAnimals = readOnlyRepo.getAll()
    println("All Animals:")
    allAnimals.forEach { animal ->
        println("- ${animal.name}")
    }

    val dog1 = Dog("Max")
    writeOnlyRepo.add(dog1)
    println("\nAdded Dog:")
    val addedDog = readOnlyRepo.getById(dog1.name)
    println("- ${addedDog?.name}")

    val cat1 = Cat("Misty")
    // writeOnlyRepo.add(cat1)  // Compilation Error: Type mismatch. Required: Dog, Found: Cat
}

在上面的代码示例中,我们定义了两个存储库接口:ReadOnlyRepositoryWriteOnlyRepositoryReadOnlyRepository接口声明了返回类型out T,表示它只能查询(读取)动物信息。WriteOnlyRepository接口声明了参数类型in T,表示它只能添加(写入)动物。

然后,我们创建了一个ReadOnlyAnimalRepository类来实现ReadOnlyRepository<Animal>接口,用于查询动物信息。同样地,我们还创建了一个WriteOnlyAnimalRepository类来实现WriteOnlyRepository<Animal>接口,用于添加动物。

main函数中,我们首先将ReadOnlyAnimalRepository赋值给readOnlyRepo变量,这是合法的,因为ReadOnlyAnimalRepository实现了ReadOnlyRepository<Animal>接口。

然后,我们将WriteOnlyAnimalRepository赋值给writeOnlyRepo变量,这也是合法的,因为WriteOnlyAnimalRepository实现了WriteOnlyRepository<Animal>接口。注意,虽然我们将其赋值给writeOnlyRepo变量,但我们仍然只能使用add方法添加

  • 7
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
C#中,async/await是一种用于处理异步操作的关键字组合。它可以使代码更加简洁和易于理解,同时也提供了更好的性能和可维护性。 下面是一些C# async/await的复杂运用场景: 1. 并行执行多个异步任务:使用Task.WhenAll方法可以并行执行多个异步任务,并等待它们全部完成。例如: ```csharp public async Task DoMultipleTasksAsync() { Task task1 = Task.Run(() => DoTask1()); Task task2 = Task.Run(() => DoTask2()); Task task3 = Task.Run(() => DoTask3()); await Task.WhenAll(task1, task2, task3); } ``` 2. 异步任务的超时处理:使用Task.Delay和CancellationToken实现异步任务的超时处理。例如: ```csharp public async Task DoTaskWithTimeoutAsync() { var cts = new CancellationTokenSource(); cts.CancelAfter(TimeSpan.FromSeconds(5)); try { await Task.Delay(TimeSpan.FromSeconds(10), cts.Token); // 执行异步任务 } catch (OperationCanceledException) { // 超时处理逻辑 } } ``` 3. 异步任务的重试机制:使用循环和延迟重试策略来实现异步任务的重试。例如: ```csharp public async Task DoTaskWithRetryAsync() { int maxRetries = 3; int retryDelaySeconds = 5; for (int retryCount = 0; retryCount < maxRetries; retryCount++) { try { // 执行异步任务 await DoTaskAsync(); return; } catch (Exception) { // 异常处理逻辑 } await Task.Delay(TimeSpan.FromSeconds(retryDelaySeconds)); } // 重试次数超过限制的处理逻辑 } ``` 这些是C# async/await的一些复杂运用场景,希望对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

董厂长

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值