From a79f6fcf4223bb0fe080081c0afa911bc5c29904 Mon Sep 17 00:00:00 2001 From: Kister Hakusan <2753888203@qq.com> Date: Wed, 22 Oct 2025 10:35:50 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0Lesson17?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- C#进阶/C#进阶.sln | 12 +++ .../Lesson17_协变逆变/Lesson17_协变逆变.csproj | 10 +++ C#进阶/Lesson17_协变逆变/Program.cs | 86 +++++++++++++++++++ .../Lesson17_协变逆变练习.csproj | 10 +++ C#进阶/Lesson17_协变逆变练习/Program.cs | 53 ++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 C#进阶/Lesson17_协变逆变/Lesson17_协变逆变.csproj create mode 100644 C#进阶/Lesson17_协变逆变/Program.cs create mode 100644 C#进阶/Lesson17_协变逆变练习/Lesson17_协变逆变练习.csproj create mode 100644 C#进阶/Lesson17_协变逆变练习/Program.cs diff --git a/C#进阶/C#进阶.sln b/C#进阶/C#进阶.sln index a94403f..8605ea8 100644 --- a/C#进阶/C#进阶.sln +++ b/C#进阶/C#进阶.sln @@ -69,6 +69,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson16_List排序", "Less EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson16_List排序练习", "Lesson16_List排序练习\Lesson16_List排序练习.csproj", "{D6D1193A-668E-454A-BFBF-6186A2C76509}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson17_协变逆变", "Lesson17_协变逆变\Lesson17_协变逆变.csproj", "{123A2A95-0776-4C76-8570-4D879159D362}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lesson17_协变逆变练习", "Lesson17_协变逆变练习\Lesson17_协变逆变练习.csproj", "{DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -207,6 +211,14 @@ Global {D6D1193A-668E-454A-BFBF-6186A2C76509}.Debug|Any CPU.Build.0 = Debug|Any CPU {D6D1193A-668E-454A-BFBF-6186A2C76509}.Release|Any CPU.ActiveCfg = Release|Any CPU {D6D1193A-668E-454A-BFBF-6186A2C76509}.Release|Any CPU.Build.0 = Release|Any CPU + {123A2A95-0776-4C76-8570-4D879159D362}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {123A2A95-0776-4C76-8570-4D879159D362}.Debug|Any CPU.Build.0 = Debug|Any CPU + {123A2A95-0776-4C76-8570-4D879159D362}.Release|Any CPU.ActiveCfg = Release|Any CPU + {123A2A95-0776-4C76-8570-4D879159D362}.Release|Any CPU.Build.0 = Release|Any CPU + {DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DDF7EBE2-4B8E-4B48-97BC-06EB4E55796A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/C#进阶/Lesson17_协变逆变/Lesson17_协变逆变.csproj b/C#进阶/Lesson17_协变逆变/Lesson17_协变逆变.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/C#进阶/Lesson17_协变逆变/Lesson17_协变逆变.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/C#进阶/Lesson17_协变逆变/Program.cs b/C#进阶/Lesson17_协变逆变/Program.cs new file mode 100644 index 0000000..aa18dab --- /dev/null +++ b/C#进阶/Lesson17_协变逆变/Program.cs @@ -0,0 +1,86 @@ +namespace Lesson17_协变逆变 +{ + #region 知识点一 什么是协变逆变 + //协变: + //和谐的变化,自然的变化 + //因为 里氏替换原则 父类可以装子类 + //所以 子类变父类 + //比如 string 变 object + //感受是和谐的 + + //逆变: + //逆常规的变化,不正常的变化 + //因为 里氏替换原则 父类可以装子类 但子类不能装父类 + //所以 父类变子类 + //比如 object 变 string + //感受是不正常的 + + //协变和逆变是用来修饰泛型的 + //协变:out + //逆变:in + //用于在泛型中 修饰 泛型字母 + //只有泛型接口和泛型委托能使用 + #endregion + + #region 知识点二 作用 + //1.返回值 和 参数 + //用 out 修饰的泛型 只能作为返回值 不能作为参数 + delegate T TestOut(); + //用 in 修饰的泛型 只能作为参数 不能作为返回值 + delegate void TestIn(T t); + //注意:只能在泛型接口和泛型委托中使用 + + interface Test + { + void TestFun(T v); + T2 TestFun2(); + } + + + + + //2.结合里氏替换原则理解 + + class Father + { + + } + + class Son : Father + { + + } + #endregion + internal class Program + { + static void Main(string[] args) + { + #region 知识点三 (结合里氏替换原则) + //协变:子类变父类 + TestOut os = () => + { + return new Son(); + }; + TestOut of = os;//不能直接装,TestOut必须通过协变的方式才能装os + Father f = of();//实际返回的是Son类型的对象 + + //逆变:父类变子类 + TestIn iF = (value) => + { + + }; + TestIn iS = iF;//不能直接装,TestIn必须通过逆变的方式才能装iF + iS(new Son());//实际传递进去的是Father类型的对象 + #endregion + } + } +} +//总结 +//协变 out +//逆变 in +//用来修饰 泛型替代符的 只能修饰接口和委托中的泛型 + +//作用两点 +//1.out修饰的泛型类型 只能作为返回值类型 in修饰的泛型类型 只能作为 参数类型 +//2.遵循里氏替换原则的 用out和in修饰的 泛型委托 可以相互装载(有父子关系的泛型) +// 协变 父类泛型委托装子类泛型委托 逆变 子类泛型委托装父类泛型委托 \ No newline at end of file diff --git a/C#进阶/Lesson17_协变逆变练习/Lesson17_协变逆变练习.csproj b/C#进阶/Lesson17_协变逆变练习/Lesson17_协变逆变练习.csproj new file mode 100644 index 0000000..2150e37 --- /dev/null +++ b/C#进阶/Lesson17_协变逆变练习/Lesson17_协变逆变练习.csproj @@ -0,0 +1,10 @@ + + + + Exe + net8.0 + enable + enable + + + diff --git a/C#进阶/Lesson17_协变逆变练习/Program.cs b/C#进阶/Lesson17_协变逆变练习/Program.cs new file mode 100644 index 0000000..25f6fc8 --- /dev/null +++ b/C#进阶/Lesson17_协变逆变练习/Program.cs @@ -0,0 +1,53 @@ +namespace Lesson17_协变逆变练习 +{ + //协变 + delegate T TestOut(); + //逆变 + delegate void TestIn(T t); + + class Father + { + + } + + class Son : Father + { + + } + internal class Program + { + static void Main(string[] args) + { + #region 练习题一 + //请简述协变逆变有什么作用 + + //协变逆变是用来修饰泛型替代符的 只存在于泛型接口和泛型委托中 + //1.协变 用 out 修饰 只能作为返回值 不能作为参数 + //2.逆变 用 in 修饰 只能作为参数 不能作为返回值 + + //遵循里氏替换原则 用out和in修饰的泛型委托如果类型是父子关系 那么可以相互装载 + // 协变:父类泛型委托变量 可以装 子类泛型委托实例 + // 逆变:子类泛型委托变量 可以装 父类泛型委托实例 + #endregion + + #region 练习题二 + //请写出协变逆变的代码示例 + + TestOut s = () => + { + return new Son(); + }; + + TestOut tf = s; + Father f = tf(); + + TestIn iF = (value) => + { + Console.WriteLine("接受到一个Father类型的参数"); + }; + TestIn iS = iF; + iS(new Son()); + #endregion + } + } +}