本文主要是介绍c# 逆变 / 协变,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
个人理解:
1. 逆变in向上兼容类
2. 协变out向下兼容类
在面向对象编程中,尤其是使用泛型时,in
和out
关键字用于限制类型参数的协变性和逆变性。
-
in
关键字(逆变):in
关键字用于标记泛型类型参数的逆变性。逆变表示可以使用指定类型的基类或超类作为方法的参数类型。- 当一个泛型类或接口使用
in
关键字限定类型参数时,该泛型类型可以被赋值给比它更通用的类型。 - 例如,如果有一个只写存储库,你无法通过它查询信息,只能往里面添加动物。这种情况下,可以将泛型类型参数声明为
in Animal
,表示该类型参数可以是Animal
或其任何基类。
-
out
关键字(协变):out
关键字用于标记泛型类型参数的协变性。协变表示可以使用指定类型的子类或派生类作为方法的返回类型。- 当一个泛型类或接口使用
out
关键字限定类型参数时,该泛型类型可以被赋值给比它更具体的类型。 - 例如,如果有一个只读存储库,你无法通过它添加动物,只能查询信息。这种情况下,可以将泛型类型参数声明为
out Animal
,表示该类型参数可以是Animal
或其任何派生类。
通过使用in
和out
关键字,我们可以在泛型类型参数中限制类型的协变性和逆变性,以确保类型安全性。这样做的好处是能够更容易地对泛型类型进行复用和灵活性。
代码示例:
// 声明一个只读存储库接口,用于查询动物信息
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
}
在上面的代码示例中,我们定义了两个存储库接口:ReadOnlyRepository
和WriteOnlyRepository
。ReadOnlyRepository
接口声明了返回类型out T
,表示它只能查询(读取)动物信息。WriteOnlyRepository
接口声明了参数类型in T
,表示它只能添加(写入)动物。
然后,我们创建了一个ReadOnlyAnimalRepository
类来实现ReadOnlyRepository<Animal>
接口,用于查询动物信息。同样地,我们还创建了一个WriteOnlyAnimalRepository
类来实现WriteOnlyRepository<Animal>
接口,用于添加动物。
在main
函数中,我们首先将ReadOnlyAnimalRepository
赋值给readOnlyRepo
变量,这是合法的,因为ReadOnlyAnimalRepository
实现了ReadOnlyRepository<Animal>
接口。
然后,我们将WriteOnlyAnimalRepository
赋值给writeOnlyRepo
变量,这也是合法的,因为WriteOnlyAnimalRepository
实现了WriteOnlyRepository<Animal>
接口。注意,虽然我们将其赋值给writeOnlyRepo
变量,但我们仍然只能使用add
方法添加
这篇关于c# 逆变 / 协变的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!