当前位置: 首页 > news >正文

C#程序员参考手册—知识点精选

1. 默认的命名空间

    命名空间是C#类、接口、委托、枚举和其他类型的一种 逻辑上的组合。如果您没有定义自己的命名空间,代码会自动放入一个没有名称的全局命名空间中。命名空间的第一部分通常是一个公司或组织的名称,第二部分应该是相关技术的名称,后面跟可选的特性和设计名。比如,如果您在Acme Engines Corporation工作,您可以这样定义您好的命名空间: AcmeEngines.FuelInjector.Diesel

2. 类的默认访问控制符internal

    类有四种访问属性:internal、private、protected和public。在命名空间中声明的类只能有pubic或internal访问属性。 没有指定访问修饰符时,类的访问类型默认为internal,即该类只能从同一个 程序集(assembly)的其它类中访问。 
    让我们来看看当类不指定访问修饰符时,其它程序集中的类对它的访问情况。首先在名为Quad.cs文件中定义一个Quad类,然后在名为Test.cs中定义一个Test类。我们试图在Test类中使用Quad类的一个实例。两个类的定义如下:

    Quad.cs文件的内容为:
using  System;

class  Quad
{
    
double width, height;

    
public Quad(double w, double h)
    
{
        width 
= w;
        height 
= h;
    }


    
public double GetArea()
    
{
        
return width * height;
    }

}
    
    Test.cs文件的内容为:
using  System;

public
class  Test
{
    
public static void Main()
    
{
        Quad q 
= new Quad(2.03.0);
        Console.WriteLine(
"Area is {0}", q.GetArea());
    }

}

    为了测试,我们将Quad.cs文件单独编译成.dll文件。方法是:
    第一步:把Quad.cs文件复制到vs.net安装的目录下面,即与C#编译器控制台csc.exe处于同一目录。笔者的系统装在D盘,所以把Quad.cs文件复制到D:\WINDOWS\Microsoft.NET\Framework\v1.1.4322目录下面。
    第二步:打开命令窗口->输入cmd到控制台->cd D:\WINDOWS\Microsoft.NET\Framework\v1.1.4322转到vs.net安装的该目录下。
    第三步:执行csc命令csc /target:library Quad.cs把程序Quad.cs编译为一个库文件Quad.dll

    对文件Test.cs首先作第一步和第二步处理。由于Test类使用了Quad类的一个实例。要访问该类,使用下面的语法编译Test类:
    csc /Test.cs /reference:Quad.dll
    但是,您会得到下面的错误信息:
    Test.cs(7,9):error CS0122:不可访问“Quad”,因为它受保护级别限制。
    Test.cs(8,42):error CS0246:找不到类型或命名空间名称“q”(是否缺少using指令或程序集引用?)
    这是因为Quad类和Test类位于不同的程序集中,而且Quad类是内部访问方式,所以Test类不能访问它。要解决这个问题,用public修改符定义Quad类就可以了:

using  System;

public  class  Quad
{
    
double width, height;

    
public Quad(double w, double h)
    
{
        width 
= w;
        height 
= h;
    }


    
public double GetArea()
    
{
        
return width * height;
    }

}


3. 三种方法创建一个类实例

    类的实例是一个引用类型的变量。因此,对象存放在堆中。
    实例化对象主要有三种方法:
    (1)  使用 new关键字。new关键字的作用是调用一个称为构造函数的特殊函数。要创建一个Test类的实例,可输入:Test mytest=new Test(); 这个语法实际上是把两个语句合二为一。语句的第一部分Test mytest创建一个Test类型的引用,名为mytest。语句的第二部分=new Test();创建一个与引用相关的Test对象,并调用没有参数的Test类的构造函数初始化该对象。
    (2) 有些类可能没有可访问的构造函数,这种情况下就不能用构造函数来实例化该对象。这些 对象的实例一般是在.NET Framework的方法 内部创建,这些方法返回对类实例的引用。例如:File类的Create()方法(一个静态方法)返回对FileStream对象的引用。可以用语法:FileStream fs=File.Create("data.inp");对一个名为data.inp的文件实例化一个FileStream对象。
    (3) 实例化对象还有一种方式— 使用反射。我们可以使用System.Type类动态检索具体类型的ConstructorInfo对象,并调用它检索类的一个实例。例如:给定一个ReflectTest类,它有一个公有的、无参数的构造函数:
public   class  ReflectTest
{
    
public ReflectTest()
    
{
 
    }

}
    
    可使用下面的代码实例化该类:
using  System;
using  System.Reflection;

public   class  ReflectTest
{
    
public ReflectTest()
    
{
 
    }

}


public   class  Application
{
    
//Get the Type object for the ReflectTest class
    Type t=Type.GetType("ReflectTest");
    
    
//Get the parameterless constructor for the class
    ConstructorInfo ctor=t.GetConstructor(System.Type.EmptyTypes);
    
//Invoke the constructor with a 'null' parameter
    
    ReflectTest test
=(ReflectTest)ctor.invoke(null);
}


4. 将构造函数声明为私有

    如果没有显式定义构造函数,系统将提供一个默认的、不带参数的public构造函数,它将把数据成员初始化为默认值。如果希望拒绝对该构造函数的仅有访问(例如:如果只希望通过工厂类实例化该类),可以用一个不同的访问级别声明这个构造函数。如果定义了一个无参的private构造函数,我们将阻止该类被实例化(这种做法可以针对这样的类:它只有静态成员,而又不能声明为abstract,因为我们想把它像System.Math类一样声明为sealed)。

5. 调用基类的构造函数

    当创建类的实例时,它的创建工作包括它的基类的创建。从基类继承的任何数据成员必须进行初始化。派生类的构造函数的一个操作是从它的直接基类中调用一个构造函数。这个操作可以使用基类的默认(无参数)构造函数隐式进行,也可以让派生类的构造函数显式调用基类的构造函数。如果类没有定义无参构造函数,就必须显式地调用一个基类的构造函数。方法是使用 :base 关键字。如:

using  System;

public   class  Quad
{
    
double width, height;

    
public Quad(double w, double h)
    
{
        width 
= w;
        height 
= h;
    }


    
public double GetArea()
    
{
        
return width * height;
    }

}


public   class  NamedQuad : Quad
{
    
string name;

    
public NamedQuad(double w, double h, string str)
        
base(w, h)
    
{
        name 
= str;
    }


    
public string GetName()
    
{
        
return name;
    }

}


public   class  BaseConstDemo
{
    
public static void Main()
    
{
        NamedQuad nq 
= new NamedQuad(2.03.0"Harry");
        Console.WriteLine(
"Area of {0} is {1}", nq.GetName(), nq.GetArea());
    }

}

运行结果:
Area of Harry is 6

    这个例子中一个有趣的地方是如果我们是这样定义NamedQuad类构造函数的:

public  NamedQuad( double  w,  double  h,  string  str)
    
{
        width 
= w;
        height 
= h;
        name 
= str;
    }

    程序不会通过编译。这是因为NamedQuad构造函数将试图从Quad类调用一个无参数的构造函数,但Quad类没有定义一个无参数的构造函数。

6. 结构和类的区别

    结构和类的主要不同在于:
    (1) 结构存放在栈中并按值传递。类的对象放在堆中,按引用传递。和类的对象相比,结构具有性能上的优势。原因之一是值类型的分配快于引用类型。原因之二是存放在栈中的值一离开作用域就立即被收回,不用等待垃圾收集器来处理。但是,结构作为参数传递给方法前会复制它的一个完整的副本,所以只能用来表示小的数据结构。而当引用类型传递给方法时,传递的只是对对象的引用。
    (2) 结构既不能定义无参数的构造函数,又不能定义析构函数。
    (3) 结构的隐式类型是sealed类型,不能被继承。虽然它们可以提供一个或多个接口的实现。

7. 接口默认的访问方式是internal

    接口为类或结构提供了蓝图。它是一个能声明属性、索引器、事件和方法的编程构造。它不为这些成员提供实现,只提供定义。实现接口的数据类型必须提供接口成员的实现。在命名空间中声明的接口可以被授予public或internal访问类型,默认的访问方式是internal。接口中声明的成员隐式地为public和abstract,它们声明时没有实现,没有访问修饰符。C#的约定是接口名以一个大写的字母“I”开始。

8. 方法中参数的修饰符(params/ref/out)

    参数按值或按引用传递。未修饰的参数按值传递,方法中变量的改变不会影响到最初的变量。但是,因为对象变量是存放在堆中的,存放在栈中的只是该位置的一个引用,所以传递给方法的是这个内存地址,而不是实际的对象,对对象的任何改变将会反映在最初的变量中。
    引用参数按引用传递给方法。这意味着传递给方法的是对对象的一个引用。在方法内部对引用类型的改变都会影响到最初的变量。
    按值传递的引用类型参数和按引用传递的参数之间的差别是很微小的。但在处理字符串时这种差异则很明显。

    8.1 params关键字
    params关键字指明一个输入参数将被看作一个参数数组。参数数组将包含数量不定的指定类型的参数。因此params关键字用于可变的参数列表行为。params关键字只能用于参数列表中的最后一个参数

    示例:params关键字
    ParamsDemo类定义了Process()方法,它只打印一个Strings数组。如果没有使用params关键字,您必须在调用该方法前创建并加载Strings数组:

using  System;

public   class  ParamsDemo
{
    
public static void Main()
    
{
        String[] s 
= new String[3];
        s[
0= "Jackson";
        s[
1= "Zachary";
        s[
2= "Erica";

        ParamsDemo.Process(s);
    }


    
public static void Process(String[] str)
    
{
        
for (int i = 0; i < str.Length; ++i)
        
{
            Console.WriteLine(str[i]);
        }

    }

}

    下面是在参数列表中使用params关键字时的程序:

using  System;

public   class  ParamsDemo
{
    
public static void Main()
    
{
        ParamsDemo.Process(
"Jackson","Zachary","Erical");
    }


    
public static void Process(params String[] str)
    
{
        
for (int i = 0; i < str.Length; ++i)
        
{
            Console.WriteLine(str[i]);
        }

    }

}

运行结果:
Jackson
Zachary
Erica

    8.2 ref关键字
    ref关键字让一个值类型的输入参数按引用传递。在方法中对变量的任何修改也将改变最初变量的值。ref关键字放在参数列表中变量类型的前面。在调用方法时也必须使用ref关键字。
    ref关键字的一个作用是取消一个方法只能返回一个值的限制。
    引用参数既传入方法,又从方法中传出,在传入前必须初始化。

    示例:ref关键字
    例子中定义了一个静态Scale(),它按指定量改变两个浮点数。两个浮点数使用ref关键字被传递给方法。当它们的值在Scale()方法内改变时,它们将在方法返回时保持这些变化。注意调用Scale()时ref关键字的使用:

using  System;

public   class  Demo
{
    
public static void Scale(double scale, ref double a, ref double b)
    
{
        a 
*= scale;
        b 
*= scale;
    }


    
public static void Main()
    
{
        
double d1, d2;
        d1 
= 2.0;
        d2 
= 3.0;

        Demo.Scale(
1.5ref d1, ref d2);

        Console.WriteLine(
"d1 is {0}", d1);
        Console.WriteLine(
"d2 is {0}", d2);

        Console.ReadKey();
    }

}

运行结果:
d1 is 3
d2 is 4.5

    我们前面说过,引用类型按值传递,但这个值是对象在内存中存储的地址。因此对对象所做的任何修改将反映在调用作用域中的变量上。然而,字符串有一些不同。因为字符串在C#中是不可变的,每当修改字符串时就会创建一个新的字符串对象。这意味着最初的变量不会受到影响(它仍将引用最初的String对象)。相似的,如果使用new关键字显式创建一个新的对象并将一个值参数指向它,这不会影响到调用作用域中的原始变量。

    引用参数在这里就不一样了(引用参数是有效的输入/输出参数),如果参数的值在方法体内修改,或者如果参数指向一个不同的对象,在方法外部的原始变量也将被更新并指向新的引用。

    示例:按引用传递字符串
    为了演示引用参数和引用类型的值参数之间的不同,下面的代码调用了两个方法,每个方法带一个字符串参数并在方法体内修改这个字符串。第一个方法接受一个值参数,第二个方法使用ref关键字接受一个引用参数:

using  System;

public   class  StringDemo
{
    
static void DoSomethingByValue(string s)
    
{
        s
="A different string";
    }


    
static void DoSomethingByReference(ref string s)
    
{
        s 
= "Another string";
    }


    
static void Main(string[] args)
    
{
        
string s = "A string";
        Console.WriteLine(s);

        DoSomethingByValue(s);        
        Console.WriteLine(s);

        DoSomethingByReference(
ref s);
        Console.WriteLine(s);

        Console.ReadKey();
    }

}

运行结果:
A string
A string
Another string

    8.3 out关键字
    在C#中,变量在使用前总是必须初始化。如果定义了一个方法,它将把一个值赋给一个输入参数,该输入变量在传递给方法前,仍必须被赋给一个哑值。使用out关键字可以避免这个无意义的步骤。
    使用out关键字修改的输入参数成为输出参数,能在初始化前传递给方法。out关键字放在方法声明语句中变量类型的前面。方法调用中也必须使用out关键字。
    输出参数在方法返回前必须被赋给一个值。

    示例:out关键字
    注意即使返回到Main()方法后,整型输出参数也保持着在SetString()方法中赋给它的值。这是因为输出参数使用的存储位置和方法调用中人微言轻参数的变量是相同的。

using  System;

public   class  OutDemo
{
    
public static void SetString(out string str, out int i)
    
{
        str 
= "Happy New Year";
        i 
= 4;
    }


    
public static void Main()
    
{
        String s;
        
int i;
        OutDemo.SetString(
out s, out i);

        Console.WriteLine(s);
        i 
+= 2;
        Console.WriteLine(i);

        Console.ReadKey();
    }

}

运行结果:
Happy New Year
6

                                                              摘自 <<C# Programmer's Reference>>

相关文章:

  • Object内存核心结构及实现完全剖析(MethodTable、EEClass与MethodDescChunk)
  • linux下net-snmp 已经安装,为什么没有 snmpwalk和snmpget
  • [第7天]继续讲,从克隆帐号 讲起
  • 只要讲信义,就有做不完的生意
  • Phoenix OS 最新更新 4/3/2008
  • 什麼是SOAP?
  • 最经典的***入门教材
  • 工控项目开发框架介绍
  • c#获取文件路径
  • 条款二 : 运行时常量(readonly)优于编译时常量(const)
  • SQL Server 2005新功能
  • 是DataGrid的某数字内容列可编辑,并且以NumericStepper组件改变数值。
  • 找工作要做的十件事
  • 什么是数据恢复技术
  • [InnoDB系列] -- SHOW INNODB STATUS 探秘
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • AngularJS指令开发(1)——参数详解
  • canvas实际项目操作,包含:线条,圆形,扇形,图片绘制,图片圆角遮罩,矩形,弧形文字...
  • css布局,左右固定中间自适应实现
  • Electron入门介绍
  • iOS高仿微信项目、阴影圆角渐变色效果、卡片动画、波浪动画、路由框架等源码...
  • Java-详解HashMap
  • jquery ajax学习笔记
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • linux安装openssl、swoole等扩展的具体步骤
  • mysql外键的使用
  • Netty源码解析1-Buffer
  • vue脚手架vue-cli
  • 笨办法学C 练习34:动态数组
  • 从零到一:用Phaser.js写意地开发小游戏(Chapter 3 - 加载游戏资源)
  • 前端工程化(Gulp、Webpack)-webpack
  • 如何用vue打造一个移动端音乐播放器
  • 协程
  • 06-01 点餐小程序前台界面搭建
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #微信小程序:微信小程序常见的配置传值
  • (007)XHTML文档之标题——h1~h6
  • (1)(1.13) SiK无线电高级配置(五)
  • (2021|NIPS,扩散,无条件分数估计,条件分数估计)无分类器引导扩散
  • (32位汇编 五)mov/add/sub/and/or/xor/not
  • (4)STL算法之比较
  • (C语言)共用体union的用法举例
  • (附源码)ssm旅游企业财务管理系统 毕业设计 102100
  • (汇总)os模块以及shutil模块对文件的操作
  • (每日持续更新)jdk api之FileReader基础、应用、实战
  • (三)mysql_MYSQL(三)
  • (五)Python 垃圾回收机制
  • (转)setTimeout 和 setInterval 的区别
  • (转)winform之ListView
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .md即markdown文件的基本常用编写语法
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • @Import注解详解