如何定义C#中类的成员

C#中类的成员

成员定义

在类定义中,也提供该类中所有成员的定义,包括字段、方法和属性。所有成员都有自己的访问级别,用下面的关键字之一来定义。
public——成员可由任何代码访问
private——成员只能由类中的代码访问(如果没有使用任何关键字,就默认使用这个)
internal——成员只能由定义它的程序集(项目)内部代码访问
protected——成员只能由类和派生类访问。
也可以使用protected internal成员只能由项目中派生类来访问。

定义字段

class MyClass
{
	public int MyInt;
}	

公共字段用PascalCasing来命名,私有字段用camelCasing来命名。
字段也可以使用关键字readonly,这表示这个字段只能在执行构造函数的过程中赋值,或由初始化赋值语句赋值

class MyClass
{
	public readonly int MyInt = 17;
}	

可使用static关键字将字段声明为静态字段,例如

class MyClass
{
	public static int MyInt;
}	

静态字段必须通过定义他们的类来访问,例如MyClass.MyInt,而不是通过这个类的对象的实例来访问,另外可以使用一个const关键字来创建一个常量值,按照定义,const成员也是静态的,所以不需要static修饰符。

定义方法

class MyClass
{
	public string GetString() => "Here is a string";
}	

注意,如果使用了static关键字,这个方法就只能通过类来访问,不能通过对象实例来访问,也可以在方法定义中使用以下关键字
virtual——方法可以重写
abstract——方法必须在非抽象的派生类中重写
override——方法重写了一个基类方法(如果方法被重写就必须使用该关键字)
extern——方法定义放在其他地方
重写方法的实例如下

public class MyBaseClass
{
	public virtual void DoSoming();
	{
		//Base implementation
	}
}
public class MyDerivedClass : MyBaseClass
{
	public override void DoSomething()
	{
		//Derived class implementation,override base implementation
	}
}				

定义属性

属性的定义方式和字段类似,但包含的内容比较多,属性拥有两个类似于函数的块,一个块用于获取属性的值,另一个块用于设置属性的值

public int MyIntProp
{
	get
	{
		//property get code
	}
	set
	{
		//Property set code
	}	
}
		

get块必须有一个属性类型的返回值,简单属性一般与私有字段相关联,此时get字段可以直接返回该字段的值。

//Field used by property
private int myInt;
//Property.
public int MyIntProp
{
	get { return myInt;}
	set { //Property set code. }
}	

外部代码不能直接访问这个myInt字段,因为其访问级别是私有的,外部代码必须使用属性来访问该字段。set函数采用类似的方式把一个值赋给字段。这里可以使用value关键字来表示用户提供的属性值

//Field used by property
private int myInt;
//Property.
public int MyIntProp
{
 get { return myInt;}
 set { myInt = value}
} 

value等于类型与属性相同的一个值,所以如果属性和字段使用相同的类型,就不必考虑数据类型的转换,要为可空整数类型提供一个默认值,可以使用这个由表达式构成的成员函数模式

private int? myInt;
public int? MyIntProp
{
	get { return myInt; }
	set {myInt = value ?? 0;}
}	

这个简单属性只是用来阻止对myInt字段的直接访问在对操作进行更多操作控制时,属性的作用才能真正发挥出来。例如

set
{
	if (value >= 0 && value <=10)
		myInt = value;
	else
		throw (new ArguementOutOfRangeException ("MyIntProp"
		,value,"MyIntProp must be assigned a value between 0 and 10"));	
}		

还可以在访问器中设置其可访问性,访问器的可访问性不能高于它所属的属性。
使用方法和属性和字段的例子

class MyClass
    {
        public readonly string Name;  
        private int intVal;
        public int Val
        {
            get { return intVal; }
            set
            {
                if (value >= 0 && value <= 10)
                    intVal = value;
                else
                    throw (new ArgumentOutOfRangeException("Val", value,
                       "Val must be assigned a value between 0 and 10."));
            }
        }
        public override string ToString() => "Name: " + Name + "\nVal: " + Val;
        private MyClass() : this("Default Name") { }
        public MyClass(string newName)
        {
            Name = newName;
            intVal = 0;
        }
        private int myDoubledInt = 5;
        public int myDoubledIntProp => (myDoubledInt * 2);
    }
class Program
    {
        static void Main(string[] args)
        {
            WriteLine("Creating object myObj...");
            MyClass myObj = new MyClass("My Object");
            WriteLine("myObj created.");
            for (int i = -1; i <= 0; i++)
            {
                try
                {
                    WriteLine($"\nAttempting to assign {i} to myObj.Val...");
                    myObj.Val = i;//使用属性的set访问器
                    WriteLine($"Value {myObj.Val} assigned to myObj.Val.");//使用属性的get访问器
                }
                catch (Exception e)
                {
                    WriteLine($"Exception {e.GetType().FullName} thrown.");
                    WriteLine($"Message:\n\"{e.Message}\"");
                }
            }
            WriteLine("\nOutputting myObj.ToString()...");
            WriteLine(myObj.ToString());
            WriteLine("myObj.ToString() Output.");
            WriteLine("\nmyDoubledIntProp = 5...");
            WriteLine($"Getting myDoubledIntProp of 5 is {myObj.myDoubledIntProp}");
            ReadKey();

        }

    }

元组析构

要实现元组析构,只要给支持该特性的任何类欠添加Deconstruct()函数即可,如下面的类所示

public class Location
{
	public Location(double latitude,double longitude)=>(Latitude,Longitude) = (latitude,longitude);
	public double Latitude { get;}
	public double Longitude {get;}
	public void Deconstruct(out double latitude,out double longitude)
	=>(latitude,longitude) = (Latitude,Longitude);
}

重构成员

添加属性时有一项很方便的技术,可以直接从字段中生成属性,“重构”表示用工具修改代码,而不是手动改
如果MyClass类包含如下字段

public string mystring;

右击该字段,选择Quick Action and Refactorings…就会修改代码为

public string MyString
{
	get=>myString;
	set=>myString = value;
}
private string myString;	

自动属性

使用下列代码可以添加一个自动属性

public int MyIntProp{get;set;}

使用自动属性时,只能通过属性访问数据,不能通过底层的私有字段来访问数据,因为我们不知道底层的私有字段的名称(该名称是在编译期间定义的),不变数据类型可以使用只有get的自动属性

public int MyIntProp{get;}

自动属性的初始化功能由以下声明字段的方式实现

public int MyIntProp{get;}=9;

类成员的其他主题

隐藏基类方法

public class MyBaseClass
{
	public void DoSomething()
	{
		//Base implementation
	}
}
public class MyDerivedClass : MyBaseClass
{
	public void DoSomething()
	{
		//Derived class implementation,hides base implementation
	}
}
	

这段代码可以正常运行,但他会生成一个警告,说明隐藏了一个基类成员。,如果确实要隐藏该成员,就可以使用new关键字显示的表明意图

public class MyDerivedClass : MyBaseClass
{
	new public void DoSomething()
	{
		//Derived class implementation,hides base implementation
	}
}	

上面两种工作方式是完全相同的,但第二种不会显示警告。,注意区别隐藏基类成员和重写他们的区别。考虑下面代码

public class MyBaseClass
{
	public virtual void DoSomething() => Write("Base imp");
}
public class MyDerivedClass : MyBaseClass
{
	public override void DoSomething() => Write("Derived imp");
}		

重写方法将替换基类中的实现代码,这样基类也将使用重写后的方法。,隐藏基类成员对于基类来说还是使用基类的方法。

接口的实现

interface IMyInterface
{
	// Interface members.
}	

接口成员的定义与类成员的定义相似,但有以下几个重要的区别:
1、不允许使用访问修饰符,所有的接口成员都是隐式公共的
2、接口成员不能包含代码体
3、接口不能定义字段成员
4、不能使用关键字static,virtual,abstract,或sealed来定义接口对象
5、类型定义成员是禁止的
但要隐藏从基接口中继承的成员,可以使用关键字new来定义它们。

interface IMyInterface
{
	void DoSomething();
}
interface IMyDerivedInterface : IMyInterface
{
	new void DoSomething();
}		

在类中实现接口
实现接口的类必须包含该接口所有成员的实现代码,且必须匹配指定的签名(包括匹配指定的get,和set块),并且必须是公共的。例如

public interface IMyInterface
{
	void DoSomething();
	void DoSomethingElse();
}
public class MyClass : IMyInterface
{
	public 	void DoSomething() {}
	public void DoSomethingElse() {}
}	

可以显式实现接口也可以隐式实现接口,隐式实现接口,接口和类都可直接访问,显式则只能使用接口来访问。

部分类定义

使用部分类定义,把类的定义放在多个文件中,可将字段、属性和构造函数放在一个文件中,而把方法放在另一个文件中,为此,包含部分类定义的每个文件中对类的使用partial关键字即可,如下所示:

public partial class MyClass { ... }

部分方法定义

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值