C# 类型的创建

时间:2021-07-24 09:14:38

  类是最普通的引用类型,最简单的声明如下所示;

  class YourNameClass

{

}

更复杂的类可以拥有以下这些选项;

置于关键字class前面的:属性(attributes)与class修饰符(class modifiers)。不可嵌套的class修饰符有public、internal、abstract、sealed、static、unsafe、以及partial

跟在YourNameClass 后面:通用类型参数(generic type parameters)、一个基类(base class)与一个或多个接口(interface)

多括号内部:类型成员(class members)(包括方法、属性、索引、事件、字段、构造函数、操作符函数、嵌套类型还有终止器)

字段

  字段就是类(class)或结构(struct)的成员变量。如:class{ string name;public int=10;}

  可以用于字段的修饰符有:静态修饰符: static、访问修饰符:public,private,protected,internal、继承修饰符:new  

              不安全代码修饰符:unsafe、只读修饰符:Readonly、线程修饰符:volatile;

  只读修饰符阻止字段在构造函数后修改。一个只读字段只有在的声明或者类型内部的构造函数中赋值。

  如:class N{Readonly static int m=12;public N(){m=13}}//compile error;无法对制度静态变量赋值。

字段初始化是可选的。没有初始化的字段有一个默认值(0、\0、null、false)。字段的初始化发生在构造函数调用之前;

同时声明多个字段(类型相同)。字段之间用逗号隔开。对于共享相同属性的修饰符字段,这是个便利的方法。

  如:static readonly int legs=8,eyes=1;

方法

  方法通过一系列语句来执行一个动作。方法接受调用者指定的参数作为输入数据的。并且将指定的返回值类型还给调用者作为输出数据。指定返回类型为void 的方法。表示不会返回任何值给他的调用者。方法也可以使用ref/out 参数作为输出数据返回给调用者。

在类型中,方法的签名必须是唯一的。方法的签名组成:由方法的名字和参数类型组成(不是参数名字,也不是返回类型(指的是void .或者其他的类型))

  方法的修饰符:

  静态修饰符: static

  访问修饰符: public internal  private protected

  继承修饰符 : new virtual abstract override sealed

  不安全代码修饰符: unsafe  extern

  重载方法:

  类型内可以重载方法(多个方法有相同的名字),只要他的签名不是相同的,

  如:void foo(int x)

    void foo(double x);

    void foo(int x,float y);

    void foo(float x,int y);

  然而有些是不能共存,是比较:

    void foo(int x);

    float foo(int x);//compile error;

  void goo(int [] x);

  void goo(params int[] y);//compile error;

  回顾下签名的定义:名字和参数类型组成。参数是指名字(foo)括号的参数类型(int x)。;

  按值传递和引用传递

  void foo(int );void foo(ref int y);//so far compile ok, void foo(out int c);//compile error;

实例构造函数

  在类型或者结构中,构造函数运行初始化代码,构造函数就普通函数那样定义,只是他的名字和返回值类型都简化为与包含的类型一致:

  public class panda{

  string name;

  public panda(string n){

  name=n;
  }

构造函数可以使用一下修饰符:

                访问修饰符:public internal private protected

                未托管代码修饰符:unsafe extern

  既然方法可以重载,构造函数是特殊的方法,也是可以重载的;

  重载构造函数:

  using System;

  public class Wine{

  public decimal Price;

  public int  Year;

  public Wine(decimal price){Price=price;}

  public Wine(decimal price,int year):this(price){Year=year;}

  当一个构造函数调用另一个构造函数时,被调用的先执行。调用形式:如例子。

  表达式本身无法引用this 引用,例如。他可以调用静态方法来调用实例。

}
}

隐式无参构造函数:

  对于类来说,当且仅当没有定义函数的时候的,C#编译器会自动产生一个无参的构造函数,只要定义至少一个构造函数,无参构造函数就不会发生。

构造函数和字段的初始化顺序:

  字段的初始化发生在构造函数之前。并且初始化顺序与声明的顺序一样。

非公有构造函数:

  构造函数不一定要是公有的。通常需要非公有构造函数的原因是,通过调用一个静态方法控制实例的创建的,这种静态方法通常用于从池中返回一个对象而不是产生一个新对象,有时用于根据不同的输入参数返回不同的类型对象,如:

  public class class1{

  class1(){}

  public static class1 create()

{

  perform custom logic here to return  an instance of class1;
}

  }

对象初始化:

  this引用:

  this引用指向实例自身。this引用也可消除歧义。

  class Pander{

  string name;

  public Pander mate;

  public void marry(Pander p){

    mate=p;

    p.mate=this;

  }

  }

public class test{string name;public test(string name){this.name=name;}}

this 引用仅在类或者结构的非静态成员中有效。

属性(attributes)

  属性的声明和字段擦不多,只是多了get{}和set{}.

  如:class test{ decimal  f;public decimal CurrentPrice{get{return f;}set{f=value;}} 

修饰属性的修饰符:

        静态修饰符:static

        访问修饰符:public internal private protected

        继承修饰符: new virtual abstract override sealed

        不安全代码:unsafe extern

只读属性和计算属性:

抽象类和接口在软件开发中用的是很频繁的,所以结合手上有的资料进行了以下的总结:

1.抽象类(abstract class)

抽象类是一种特殊的类,有如下的特点:

.抽象方法制作声明,不包含具体的实现,可以看做是没有重写的虚方法.

.抽象类不能被实例化.具有其他类相同的特性.

.抽象类可以没有抽象方法和抽象属性,但是一旦有了抽象方法,就一定要把这个类声明为抽象类.

.具体派生类必须要覆盖基类的抽象方法.

.抽象类可以派生自另一个抽象类,可以覆盖基类的抽象方法也可以不覆盖,如果覆盖,则其他派生类也必须覆盖他们.

2.接口(interface)

接口是引用类型的,类似抽象类但又不同于抽象类.

.不能被实例化.

.只能包含实现的方法声明.

.成员可以包括方法,属性,索引器和事件.

.接口中不能包含常量,字段(域),构造函数,析构函数或者静态成员.

.接口中的所有成员默认为是public,因此接口中不能有private修饰符.

.派生类必须实现接口中的所有成员.

.一个类可以直接实现多个接口,接口之中用逗号隔开.

.一个接口可以有多个父接口,实现该接口的类必须实现所有接口中的所有成员.

3.抽象类和接口的区别

.都可以被继承.

.都不能被实例化.

.都可以包含方法声明.

.派生类必须要实现未实现的方法.

4.抽象和接口的区别

.抽象类是一个不完整的类,需要进一步细化,而接口只是一个行为的规范或规定,微软的自定义接口总是带able字段,证明其是表述一类"我能做...".

.抽象类可以定义字段,属性和方法实现.接口只能定义属性,索引器,事件和方法声明,不能包含字段.

.抽象类更多的是定义在一系列紧密相关的类之间,而接口大多数是定义在关系疏松但是都实现某一功能的类中.

.接口基本上不具备继承的任何具体特点,他仅仅承诺了能够调用的方法.

.接口可以被多重实现,抽象类只能被单一继承.即一个类一次可以实现多个接口,但是只能继承与一个父类.

.接口可以用于支持回调,而继承并不具备这个特点.

.抽象类不能被密封.

.抽象类实现的具体方法默认为虚的,但实现接口的类中的接口方法却默认为非虚的,也可以声明为虚的.

.接口与非抽象类类似.抽象类也必须为在该类的基类列表中列出的接口的所有成员提供他自己的实现.但是,允许抽象类将接口方法映射到抽象方法上.

.如果抽象类实现接口,则可以把接口中的方法映射到抽象类中作为抽象方法而不必实现,而在抽象类中的子类中实现接口中的方法.

5.抽象类和接口的使用

.抽象类主要用于关系密切的对象;而接口用于为不相关的类提供通用功能.

.如果要设计大的功能单元,则使用抽象类;如果要在组件的所有实现间提供通用的已实现功能,则使用抽象类.

.如果创建的功能将在大范围的全异对象间使用,则使用接口.如果要设计笑而简练的功能块,则使用抽象类.

.如果预计要创建组件的多个版本,则创建抽象类.抽象类提供简单的方法来控制组件版本.

.好的接口定义应该是具有专一功能性的,而不是多功能的,否则会造成接口污染.如果一个类只是实现了这个接口中的一个功能,而不得去实现接口中的其他方法,那么就叫接口污染.

.尽量避免使用继承来实现组建功能,而是使用黑箱复用,即对象组合.因为继承的层次增多,造成最直接的后果就是当你调用这个类群中的某个类时,就必须把他们全部加载到栈中!后果可想而知了.同时,可以留意到微软在构建一个类时,很多都是时候都是用到对象组合的方法.例如:asp.net中的Page类,有Server,Request等属性,但其实他们都是某个类的对象.使用Page类的对象来调用另外的类的方法和属性,是一个非常基本的设计原则.

抽象类转载http://www.cnblogs.com/zhangzhongxi/archive/2011/04/25/2028501.html

抽象类abstract

  C#中的abstract类不能被实例化,他只提供其他类的继承的接口

using System;
abstract class MyAbs
{
public void NonAbMethod()
{
Console.WriteLine("Non-Abstract Method");
}
}

class MyClass : MyAbs
{
}

class MyClient
{
public static void Main()
{
//MyAbs mb = new MyAbs();//不能实例化

MyClass mc = new MyClass();
mc.NonAbMethod();
}
}

一个抽象类可以包含abstract方法,也可包含实例化方法,但继承类(非抽象)必须实现abstract方法
using System;

abstract class MyAbs
{
public void NonAbMethod()
{
Console.WriteLine("Non-Abstract Method");
}
public abstract void AbMethod(); // 抽象方法,只有声明,没有实现
}

class MyClass : MyAbs//必须实现抽象方法
{
public override void AbMethod()
{
Console.WriteLine("Abstarct method");

}

class MyClient
{
public static void Main()
{
MyClass mc = new MyClass();
mc.NonAbMethod();
mc.AbMethod();
}
}

当然继承类也可以是抽象的

using System;

abstract class MyAbs
{
public abstract void AbMethod1();
public abstract void AbMethod2();
}

//抽象继承类不必全部实现抽象方法,部分实现便可

abstract class MyClass1 : MyAbs
{
public override void AbMethod1()
{
Console.WriteLine("Abstarct method #1");

}

class MyClass : MyClass1
{
public override void AbMethod2()
{
Console.WriteLine("Abstarct method #2");
}
}

class MyClient
{
public static void Main()
{
MyClass mc = new MyClass();
mc.AbMethod1();
mc.AbMethod2();
}
}

抽象类可以继承自非抽象类

using System;

class MyClass1 
{
public void Method1()
{
Console.WriteLine("Method of a non-abstract class");
}
}

abstract class MyAbs : MyClass1 
{
public abstract void AbMethod1(); 
}

class MyClass : MyAbs//实例类必须实现抽象方法
{
public override void AbMethod1()
{
Console.WriteLine("Abstarct method #1 of MyClass");
}
}

class MyClient
{
public static void Main()
{
MyClass mc = new MyClass();
mc.Method1();
mc.AbMethod1();

}
}

抽象类可以实现接口

using System;

interface IInterface
{
void Method1();
}

abstract class MyAbs : IInterface
{
public void Method1()
{
Console.WriteLine("Method implemented from the IInterface");
}
}

class MyClass : MyAbs 
{

}

class MyClient
{
public static void Main()
{
MyClass mc = new MyClass();
mc.Method1();
}
}

最后需要注意的是抽象类不能声明为sealed,这两个语义是冲突的。抽象方法不必(也不能)声明为virtual,因为它缺省隐含就为virtual! 

转自:http://www.cnblogs.com/zzy2740/archive/2005/09/20/240808.html 

new与virtual 相比较

如下栗:

  public class baseClass

{

  public virtual void Foo(){}
}

public class override:baseClass

{

  public override void Foo(){}
}

public class New:baseClass

{

  public new void Foo(){}
}

请思考下覆写(override)和屏蔽(new)的区别;

  override override=new override();

  baseClass bl=overrider;

  override.Foo();//compile overrider.Foo;

  bl.Foo();//compile overrider.Foo;

  ///********************************////

  New new1=new New();

  baseClass bl=new1;

  new1.Foo();//compile new1.Foo;

  bl.Foo();//compile b1.Foo;

base 关键字:

  base主要有两个目的:

  1、调用被子类覆写的成员函数;

  2、调用基类的构造函数;

public class baseclass

{

  public virtual void Method(){}
}

public class subclass:baseclass

{

  base.Method();//baseclass of Method;

  public sealed override void Method(){}
}

构造函数与继承

  子类必须包含自己的构造函数;

  

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace ConsoleApplication146 {

public class baseClass     {

public int x;

public baseClass (int x)

{             this.x = x;

}

}     public class SubClass:baseClass

{         public SubClass(int x) : base(x) { }

}     class Program     {

static void Main(string[] args)

{             SubClass a = new SubClass(123);

     Console.WriteLine(a.x);

        Console.Read();                     }

}

}

基类的初始化总是发生在子类的之前。

如果子类的构造函数忽略了base关键字,基类的无参构造函数就会被隐式调用。

public class baseclass{

  public int X;

  public baseClass(){x=1;}
}

public class SUbclass:baseClass{

  public SUbclass(){Console.WriteLine(X);}
}//compile x=1;

构造函数与成员域初始化的顺序。

  1、从子类型到基类型:

    a、成员域初始化;

    b、构造函数初始化;

  2、从基类型到子类型:

    构造函数体被执行。

public class BaseClass

{

    int x;        //first threeinitial;

    public BaseClass() //first four initial;

{

    .......................;   //first five go;
} 
}

public class SubClass:BaseClass

{

  int y;                                  //first one initial;

  public SubClass()      //first two initial;

{

  .......................;        //first six go;
}
}