(1)new List并不是null,可以正常的被遍历和AddRange

class Program
{
public static void Main()
{
//var t = new test();
//t.b = 100;
//Console.WriteLine($"{t.b}");
var a = new List<int> { 1, 2 };
var b = new List<int>();
a.AddRange(b);
foreach (var c in b)
{
Console.WriteLine($"{c}"); }
Console.WriteLine($"{b.Count}");
Console.WriteLine($"{b == null}"); }
}

(2)属性可以被private访问修饰符修饰,但这样就不能被实例从外部访问,一般是public或protected。

 class test
{
private int a { get; set; } public int b { get { return a; } set { a = 100; } }
}
class Program
{
public static void Main()
{ var t = new test();
Console.WriteLine($"{t.a}");
t.b = 100;
Console.WriteLine($"{t.b}"); }
}

(3)for 循环

int a = 1;
for (int i = 1; i < a; i++)
{
Console.WriteLine("h");
}

一次也没运行,for 循环的执行顺序是:

for (Initializer;TestExpr;IterationExpr)
Statement

在for 循环的开始,执行一次Initializer,然后对TestExpr求值,如果它返回true,执行Statement,接着是IterationExpr,然后控制回到循环的顶端,再次对TestExpr求值,依次进行,直到返回false,就继续执行Statement之后的语句。

(4) 虚方法与覆写方法,基类访问

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApp1
{ class A
{
public virtual void Print()
{
Console.WriteLine("this is a");
}
}
class B:A
{
public override void Print()
{
Console.WriteLine("this is b");
}
}
class Program
{ public static void Main()
{ B b= new B();
A a = (A)b;
a.Print();
B c = (B)a;
c.Print(); } }
}

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApp1
{ class A
{
public void Print()
{
Console.WriteLine("this is a");
}
}
class B:A
{
new public string Print()
{
Console.WriteLine("this is b");
return "yes";
}
}
class Program
{ public static void Main()
{ B b= new B();
A a = (A)b;
a.Print();
B c = (B)a;
c.Print(); } }
}

虚方法与覆写方法是成对存在的,并且要求函数除了签名一样,返回类型也一样,在派生类转为基类时,调用转化后的基类的虚方法,调用的是派生类的覆写方法。而使用new来屏蔽基类函数,则不要求返回类型一样,只要签名一样就可以了,并且派生类转为基类后,调用转化后的基类的“被屏蔽的方法”就是基类的“被屏蔽的方法”,而不再是派生类的方法。

(5)虚方法,抽象类,接口对实现多态的一点感想

多态就是:允许将子类类型的指针赋值给父类类型的指针。也就是同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。在运行时,可以通过指向基类的指针,来调用实现派生类中的方法。

  • a 首先,我们先来看下怎样用虚方法实现多态

    我们都知道,喜鹊(Magpie)、老鹰(Eagle)、企鹅(Penguin)都是属于鸟类,我们可以根据这三者的共有特性提取出鸟类(Bird)做为父类,喜鹊喜欢吃虫子,老鹰喜欢吃肉,企鹅喜欢吃鱼。创建基类Bird如下,添加一个虚方法Eat(),依次对Magpie,Eagle,Penguin添加重载方法。
    /// <summary>
/// 鸟类:父类
/// </summary>
public class Bird
{
/// <summary>
/// 吃:虚方法
/// </summary>
public virtual void Eat()
{
Console.WriteLine("我是一只小小鸟,我喜欢吃虫子~");
}
}

最后

    static void Main(string[] args)
{
//创建一个Bird基类数组,添加基类Bird对象,Magpie对象,Eagle对象,Penguin对象
Bird[] birds = {
new Bird(),
new Magpie(),
new Eagle(),
new Penguin()
};
//遍历一下birds数组
foreach (Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}

以上程序也体现了开放封闭原则,如果后面的同事需要扩展我这个程序,还想再添加一个猫头鹰(Owl),很容易,只需要添加一个Owl类文件,继承Bird,重写Eat()方法,添加给父类对象就可以了。至此,该程序的扩展性得到了提升,而又不需要查看源代码是如何实现的就可以扩展新功能。这就是多态带来的好处。

  • b 来看下利用抽象如何来实现多态

    还是刚才的例子,我们发现Bird这个父类,我们根本不需要使用它创建的对象,它存在的意义就是供子类来继承。所以我们可以用抽象类来优化它。

    我们把Bird父类改成抽象类,Eat()方法改成抽象方法。代码如下:
    /// <summary>
/// 鸟类:基类
/// </summary>
public abstract class Bird
{
/// <summary>
/// 吃:抽象方法
/// </summary>
public abstract void Eat();
}

Main主函数中Bird就不能创建对象了,代码稍微修改如下:

        static void Main(string[] args)
{
//创建一个Bird基类数组,添加 Magpie对象,Eagle对象,Penguin对象
Bird[] birds = {
new Magpie(),
new Eagle(),
new Penguin()
};
//遍历一下birds数组
foreach (Bird bird in birds)
{
bird.Eat();
}
Console.ReadKey();
}

由此可见,我们选择使用虚方法实现多态还是抽象类抽象方法实现多态,取决于我们是否需要使用基类实例化的对象.

  • c接口实现多态

我要问一个问题,喜鹊和老鹰都可以飞,这个飞的能力,我怎么来实现呢?

XXX答:“在父类Bird中添加一个Fly方法不就好了~~”

我再问:“好的,照你说的,企鹅继承父类Bird,但是不能企鹅不能飞啊,这样在父类Bird中添加Fly方法是不是不合适呢?”

XXX答:“那就在能飞的鸟类中分别添加Fly方法不就可以了吗?”

对,这样是可以,功能完全可以实现,可是这样违背了面向对象开放封闭原则,下次我要再扩展一个鸟类比如猫头鹰(Owl),我还要去源代码中看下Fly是怎么实现的,然后在Owl中再次添加Fly方法,相同的功能,重复的代码,这样是不合理的,程序也不便于扩展;

其次,如果我还要添加一个飞机类(Plane),我继承Bird父类,合适吗?

很显然,不合适!所以我们需要一种规则,那就是接口了,喜鹊,老鹰,飞机,我都实现这个接口,那就可以飞了,而企鹅我不实现这个接口,它就不能飞~~

好,接下来介绍一下接口如何实现多态~

添加一个接口IFlyable,代码如下:

    /// <summary>
/// 飞 接口
/// </summary>
public interface IFlyable
{
void Fly();
}

在Main主函数中,创建一个IFlyable接口数组,代码实现如下:

    static void Main(string[] args)
{
//创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象
IFlyable[] flys = {
new Magpie(),
new Eagle()
};
//遍历一下flys数组
foreach (IFlyable fly in flys)
{
fly.Fly();
}
Console.ReadKey();
}

所以有人称接口让C#成为多重继承也是有一定道理的。

飞机也能飞,继承Bird不合适的问题,现在有了接口,这个问题也可以解决了。如下,我添加一个飞机Plane类,实现IFlyable接口,代码如下:

    /// <summary>
/// 飞机类,实现IFlyable接口
/// </summary>
public class Plane:IFlyable
{
/// <summary>
/// 实现接口方法
/// </summary>
public void Fly()
{
Console.WriteLine("我是一架飞机,我也能飞~~");
}
}

在Main主函数中,接口IFlyable数组,添加Plane对象:

class Program
{
static void Main(string[] args)
{
//创建一个IFlyable接口数组,添加 Magpie对象,Eagle对象,Plane对象
IFlyable[] flys = {
new Magpie(),
new Eagle(),
new Plane()
};
//遍历一下flys数组
foreach (IFlyable fly in flys)
{
fly.Fly();
}
Console.ReadKey();
}
}

(6)as 和is关键字

C# 提供 is 和 as 运算符来进行转换。可以使用这两个运算符来测试强制转换是否会成功,而没有引发异常的风险。

is 运算符检查对象是否与给定类型兼容,重点是检查,只是检查.

eg:if(b is B)将检查对象b 是否为B类型的一个实例,或者是从B派生的一个类型的实例

as 运算符用于在可兼容的引用类型之间执行类似于强制类型转换的操作,重点是操作。与强转不同的是,当转换失败时,as 运算符将返回NULL空,而不是引发异常。

(7) static void Main(string[] args)

string[]args:这是用来接收命令行传入的参数。string[]是声明args的数据类型,可以存储字符串数组。在Visual studio中,可以右键项目--属性--调试---应用程序参数来进行设置。


using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace ConsoleApp
{
struct Simple
{
public int X;
public int Y;
} class SimpleClass
{
public int X;
public int Y;
}
class test { }
class Program
{ public static void Main(string[] args)
{
foreach (string s in args)
{
Console.WriteLine(s);
} } }
}

(8)不是只声明的对象不能用,是只声明的局部变量不可以用,只声明的字段如果是引用类型,那么它就是null。



如上图所示,由于在Main入口函数中,声明变量都是局部变量,所以不赋值,就不可使用,也不可拿来与null比较。

相反,在类中只声明的字段,而不赋值,那么引用类型默认就是null,值类型就是相应的默认值,如上图。

(9) 类内定义的委托和类,在外部归类所有,而非实例所有

    class test
{
public class test1 { }
public delegate void test2();
} class Program
{
public static void test3() { } public static void Main(string[] args)
{
var aa = new test();
var bb = new test.test1();
var cc = new test.test2(test3);
}

(10)重载Equals方法,与==不同的是,==对于值类型只检查是否值一样,对于引用类型,只检查引用地址是否一样。也要注意到private限定的是只有在本类内部才能被看到

    public class test
{
private int data;
public test(int data)
{
this.data = data;
}
//public bool Equals(test rhs)
//{
// return this.data == rhs.data;
//}
}
class Program
{
public static void Main()
{
var a = new test(10);
var b = new test(9);
var c = new test(10);
Console.WriteLine(a.Equals(b));
Console.WriteLine(a.Equals(c));
}
}

out:

False
False

重载Equals()方法

    public class test
{
private int data;
public test(int data)
{
this.data = data;
}
public bool Equals(test rhs)
{
return this.data == rhs.data; // data被限定为private,但在本类内部,依然可以用传过来的rhs实例来访问private data.
}
}
class Program
{
public static void Main()
{
var a = new test(10);
var b = new test(9);
var c = new test(10);
Console.WriteLine(a.Equals(b));
Console.WriteLine(a.Equals(c));
}
}

out:

False
True

(11)C#嵌套类

1.基本概念

    嵌套类:在一个类中定义另一个类,分为静态嵌套类(使用少)和非静态嵌套类(又称内部类)。 

    内部类: (1) 在一个类中直接定义类。

                (2) 在一个方法中定义类。

                (3) 匿名内部类。
  1. 嵌套类的使用

    (1)外部类只能够访问嵌套类中修饰符为public、internal的字段、方法、属性。示例如下

     public class Animal

    {

    static void Set_Animal()

    {
    //编译正确 Monkey._high = 123; Monkey._age = 4; //编译失败 Monkey._name = "hoho"; } private class Monkey {
    private static string _name; protected string _sex; internal static int _age; public static int _high; public Monkey() { } public void show() { } }

    }

(2)嵌套类可以访问外部类的方法、属性、字段而不受访问修饰符的限制

   public class Animal

{
private static int _Age; private string name; private static void DoSomething() {
Console.WriteLine(_Age); } private void DoStr() {
monkey.method(this); } /*嵌套类 定义*/ class monkey {
public static void method(Animal a) {
_Age = 23; //静态成员 a.name = "test"; //实例成员 } } }
  1. 嵌套类访问外部类实例的方法、字段、属性时候。一般在采取构造函数输入外部类

     public class Animal
{
private string _name; //*嵌套类 定义*/ class monkey {
public monkey(Animal a) {
a._name = "test"; } } }

4.继承类可以再定义一个内嵌类并从继承父类中嵌套类

 public class Animal

{
//*嵌套类 定义*/ protected class monkey {
public virtual void Method() {
Console.WriteLine("monkey"); } } } public class S_Animal : Animal {
class s_monkey :monkey {
public override void Method() {
Console.WriteLine("s_monkey"); } } }注:因为S_Animal 继承于Animal ,因此s_monkey可以继承monkey类,从而获取重写父嵌套类的机会。但是monkey必须是可继承类及可访问的(非private 、sealed、static)。 嵌套类可以随意外部类的任何数据属性,而外部类访问嵌套类就只能遵守访问修饰符。从这个角度看,嵌套类是外部类的补充,通过嵌套类可以获取更好的封装性,增加外部类的可维护性和可读性。 从程序结构看,嵌套类在逻辑上更加接近使用类。可以更有效地表示类与类之间的紧密程度。为类管理提供除命名空间外的另一种方法。 5.单例模式(singleton)就采用一种为 延迟加载初始化实例 的方法如下: public class Animal {
public Animal(){} public static Animal Intance {
get { return monkey._intance; } } class monkey {
public readonly static Animal _intance = new Animal(); } }注: 延迟加载 嵌套类的静态构造函数不会随着外部类的触发而初始化。因此可以有效地避免创建时候初始化时间,当需要使用内嵌类的时候,嵌套类才开始初始化。 6.反射内嵌类需要使用"+"而不是我们常使用的"." 。 namespace AnimalClass {
public class Animal {
public class monkey {
protected void Method() {
//do something... } } } } 注://成功 object o1 = System.Activator.CreateInstance("AnimalClass", "AnimalClass.Animal+monkey"); //失败 抛出System.TypeLoadException 异常 object o2 = System.Activator.CreateInstance("AnimalClass", "AnimalClass.Animal.monkey");

(12)null也可以进行类型转换

string s = null;
object ss = (object)s;
string sss = (string)ss;
if (sss == null) Console.WriteLine("yes");

控制台显示“yes"

C# 基础问题汇集的更多相关文章

  1. git下的团队合作模型及git基础知识汇集

    https://www.atlassian.com/git/tutorials/syncing/git-fetch Syncing svn使用单个中央库来作为开发者之间沟通的桥梁,而协同合作是通过在开 ...

  2. CSS 基础知识点 样式 选择器 伪类

    CSS 基础知识点汇集 版权声明:这篇博客是别人写的,大神博客地址 : https://www.cnblogs.com/Mtime/p/5184685.html 1.CSS 简介 CSS 指层叠样式表 ...

  3. socket和多线程编程资料汇集-基础篇

    0 基础 CS结构的分析,server端和client的选取. 1 查看端口是否链接 netstat -an|grep portid 2 root用户抓包 tcpdump port -w fn.cap ...

  4. 【JavaSE】Java基础·疑难点汇集

    Java基础·疑难点 2019-08-03  19:51:39  by冲冲 1. 部分Java关键字 instanceof:用来测试一个对象是否是指定类型的实例. native:用来声明一个方法是由与 ...

  5. java基础概念经典题目汇集

    1.下面是People和Child类的定义和构造方法,每个构造方法都输出编号.在执行new Child("mike")的时候都有哪些构造方法被顺序调用?请选择输出结果 ( ) cl ...

  6. .Net 大型分布式基础服务架构横向演变概述

    一. 业务背景 构建具备高可用,高扩展性,高性能,能承载高并发,大流量的分布式电子商务平台,支持用户,订单,采购,物流,配送,财务等多个项目的协作,便于后续运营报表,分析,便于运维及监控. 二. 基础 ...

  7. 详解Maple中的基础工具栏

    鉴于Maple 强大的符号计算功能,越来越多的人选择使用Maple 2015计算复杂的数学问题,初学者刚开始时需要对Maple有所熟悉才能很好地进行运用,下面就从基础开始,介绍Maple工作环境. M ...

  8. UML基础与Rose建模实训教程

    目  录 第1章  初识UML. 1 1.1 初识UML用例图... 1 1.2 初识UML类图... 3 第2章  Rational Rose工具... 6 2.1 安装与配置Rational Ro ...

  9. 资源 | 数十种TensorFlow实现案例汇集:代码+笔记

    选自 Github 机器之心编译 参与:吴攀.李亚洲 这是使用 TensorFlow 实现流行的机器学习算法的教程汇集.本汇集的目标是让读者可以轻松通过案例深入 TensorFlow. 这些案例适合那 ...

  10. SOA之(3)——面向服务计算基础

    面向服务计算基础(Service-Oriented Computing Fundamentals) 面向服务的计算(Service-Oriented Computing) 面向服务的计算是一个伞状术语 ...

随机推荐

  1. 基于Openframeworks调取摄像头方式的定时抓拍保存图像方法小结

    这次是采用Openframeworks来调取摄像头画面并抓图保存. 开始 借向导自动生成代码,因为要调取摄像头设备,因此增添ofVideoGrabber对象声明,又因为保存需求,所以还需添加ofPix ...

  2. 一文搞懂 MCP Servers

    一文搞懂 MCP Servers 什么是MCP MCP概念 MCP(Model Context Protocol,模型上下文协议)是由 Anthropic 提出并于 2024 年 11 月开源的一种通 ...

  3. ABC393C题解

    大概评级:橙. 送分题. 题意就是让你统计有多少条边是重边或自环. 设 \(u_i\) 表示第 \(i\) 条边的左端点,\(v_i\) 表示第 \(i\) 条边的右端点. 那么如果 \(u_i = ...

  4. Elasticsearch搜索引擎学习笔记(一)

    核心概念 ES -> 数据库 索引index -> 表 文档 document -> 行(记录) 字段 fields -> 列 安装Elasticsearch 1. 上传后解压 ...

  5. linux安装lspci

    点击查看代码 `lspci` 是一个用于在Linux系统中显示所有PCI总线以及已连接设备信息的命令.这个工具通常包含在 `pciutils` 包里.如果你需要在你的Linux系统上安装 `lspci ...

  6. Java中的JDK、JRE及JVM的简介及功能

    JDK: JDK(Java Development Kit) 是 Java 语言的软件开发工具包(SDK).没有JDK的话,无法编译Java程序(指java源码.java文件),如果想只运行Java程 ...

  7. rust学习笔记(7)

    crate 中文是货箱,这是我们编写自己的库或者程序的方式 库 使用rustc可以把一个文件编译为lib rustc --crate-type=lib rary.rs 构建的方式选择lib 编译出来的 ...

  8. Arrays工具类教你优雅地管理数组数据

    数组专用工具类指的是 java.util.Arrays 类,基本上常见的数组操作,这个类都提供了静态方法可供直接调用.毕竟数组本身想完成这些操作还是挺麻烦的,有了这层封装,就方便多了. package ...

  9. idea 缺失右侧maven窗口

    最近整了一个别人的项目到本地,发现在git下载项目到本地后,再通过idea的打开项目后,缺失了右侧的maven窗口. 注: idea是有安装到maven(idea默认是已经安装好的) 打开的项目也是m ...

  10. ant design pro git提交error; Angular 团队git提交规范

    前言 在使用 ant design pro 时,git 提交报错 > running commit-msg hook: fabric verify-commit ERROR 提交日志不符合规范 ...