c# 字段和方法设计建议

 更新时间:2020-11-19 14:49:33   作者:佚名   我要评论(0)

1、不要为抽象类提供公开的构造方法
  抽象类可以有构造方法,但是抽象类不能实例化。如果编程人员没有制定构造方法,编译器会自动生成一个默认的protected构造方

1、不要为抽象类提供公开的构造方法

  抽象类可以有构造方法,但是抽象类不能实例化。如果编程人员没有制定构造方法,编译器会自动生成一个默认的protected构造方法。下面是一个标准的简单抽象类:

abstract class MyAbstractClass
{
  protected MyAbstractClass( ) { }
}

  抽象类的构造方法不应该是public或internal的。抽象类设计的本意是只能让子类继承,而不是用于生成实例对象。如果抽象类是public或者internal的,它对于其他类型来说就是可见的,而这是不必要的,多余的。抽象类只需对子类可见即可。

2、可见字段应该重构为属性

  字段与属性有本质的区别,属性是方法。如下面的Person类型:

class Person
{
  public string Name { get; set; }
}

  编译器针对属性Name编译后,会生成一个字段和两个方法。

  属性相对于字段有如下优势:

    1)可以为属性添加代码。属性是方法,所以可以在方法内对设置或获取属性的过程进行编写代码控制。如事件支持等。

    2)可以让属性支持线程安全。要让属性变成线程安全的,可以让类型自身去实现。如果让字段支持线程安全,就只有依靠调用者本身实现。

    3)属性得到VS编译器支持,能实现自动属性的功能。自动属性的特点在LINQ中应用十分广泛,在匿名类型中,它只能实现只读的自动属性,但字段不支持。

    4)从设计的角度(面向对象),公开的字段也应该使用属性。改变字段的状态,类型不会被通知到;而改变属性的值,类型支持则会被通知。

  综上,如果一个类型存在一个可见字段,那么它应该被重构为属性。如果某个属性只对内部可见,但不涉及上面4点,则建议使用字段。

3、区别对待override和new

  override和new使类型体系因为继承而呈现出多态性。多态是“面向对象语言”的三个重要特性之一。多态要求子类具有与基类方法同名的方法,而override和new的有如下作用:

    1)如果子类中的方法前面带有new关键字,则该方法被定义为独立于基类的方法。

    2)如果子类中的方法前面带有override关键字,则子类的对象将调用该方法,而不是调用基类的方法。

  如果,对于父类的方法在子类中使用了new关键字,则两个方法相互独立。此时,使用子类类型的对象调用方法时,程序执行的将是子类类型new的方法代码;而如果将子类类型转换为父类类型后,对象调用方法时将执行的是父类的方法代码。

  如果使用了override关键字重写方法,那么不论子类类型的对象是否转换为父类类型,调用方法时都将执行的是子类的代码。

  如果对于子类中,声明与父类相同函数名称的方法,但并不使用关键字new和override。编译器在编译后会提出警告,但不影响程序运行。此时,编译器会默认为是new的效果,所以输出和显示设置与new的效果一样。

4、避免在构造方法中调用虚成员

  在构造方法中调用虚成员会出现意想不到的错误。

class Program
 {
   static void Main(string[] args)
   {
     Chinese chinese = new Chinese();
   }
 }

 class Person
 {
   public Person()
   {
     InitSkin();
   }

   protected virtual void InitSkin()
   {
     //省略
   }
 }

 class Chinese:Person
 {
   Rece Rece;

   public Chinese():base()
   {
     Rece = new Rece() { Name = "赵铭" };
   }

   protected override void InitSkin( )
   {
     Console.WriteLine(Rece.Name);
   }
 }

 class Rece
 {
   public string Name { get; set; }
 }

  运行该示例,会出现NullReferenceException:未将对象引用设置到对象的实例。

  在调用代码中,需要创建一个Chinese的实例对象chinese。由于Chinese类型有基类Person,所以运行时首先调用基类的构造方法。在基类的构造方法中,构造函数会调用InitSkin虚方法。在程序运行时,调用的是子类的InitSkin方法。在子类的InitSkin方法中又在使用子类的Rece变量。但这个时候,子类的构造函数还没调用,因此Rece变量未实例化,但是InitSkin方法又在使用Rece变量,导致错误。

5、成员应优先考虑公开的基类型或接口

  类型成员在优先考虑公开基类型或接口,会使得类型支持更多的应用场合。

  FCL中的集合类型根据功能划分有List<T>、Dictionary<TKey, TValue>、HashSet<T>等。例如,需要清空集合中的元素,返回空集合的方法Empty,如果不返回基类型或者接口的情况下,就要求我们为每个集合类型都实现该方法。但是,在FCL中实现了一个静态类型Enumerable,代码如下:

 public static IEnumerable<TResult> Empty<TResult>()
 {
   return EmptyEnumerable<TResult>.Instance;
 }

  使用了泛型接口IEnumerable,所以所有集合子类都可以不实现自己的Empty方法,做到项目的灵活应用。

6、重写时不应使用子类参数

  重写时,如果使用了子类参数,可能会偏离设计者的预期目标。

  如存在以下继承体系:

class Employee
{
}

class Manager:Employee
{
}

class Salary
{
  public void SetSalary(Employee e)
  {
    Console.WriteLine("职员被设置了薪水。");
  }
}    

class ManagerSalary:Salary
{
  public void SetSalary(Manager e)
  {
    Console.WriteLine("经理被设置了薪水。");
  }
}

  类型ManagerSalary中的SetSalary方法重写了Salary中的相同方法,但是参数采用了一个子类的参数。现在在程序中调用代码如下:

public static void Main()
{
  ManagerSalary m = new ManagerSalary();
  m.SetSalary(new Employee());
}

  设计者的本意时为经理设置对应的薪水,但是实际调用的代码却设置了员工的薪水。因此,在重写时使用子类参数有一定的风险。正确的方法时仍旧使用Employee类型参数,让编译器提醒我们要使用关键字new。

以上就是c# 字段和方法设计建议的详细内容,更多关于c# 字段和方法的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:
  • C#中sqlDataRead 的三种方式遍历读取各个字段数值的方法
  • C#实体对象序列化成Json并让字段的首字母小写的两种解决方法
  • C#程序连接数据库及读取数据库中字段的简单方法总结
  • 用C#将图片保存至Oracle BLOB字段中的方法
  • C#更新SQLServer中TimeStamp字段(时间戳)的方法
  • C#实现利用反射简化给类字段赋值的方法
  • C# Dynamic关键字之:调用属性、方法、字段的实现方法
  • C#三种判断数据库中取出的字段值是否为空(NULL) 的方法

相关文章

  • c# 字段和方法设计建议

    c# 字段和方法设计建议

    1、不要为抽象类提供公开的构造方法   抽象类可以有构造方法,但是抽象类不能实例化。如果编程人员没有制定构造方法,编译器会自动生成一个默认的protected构造方
    2020-11-19
  • 如何扩展Spring Cache实现支持多级缓存

    如何扩展Spring Cache实现支持多级缓存

    为什么多级缓存 缓存的引入是现在大部分系统所必须考虑的 redis 作为常用中间件,虽然我们一般业务系统(毕竟业务量有限)不会遇到如下图 在随着 data-size 的增大和
    2020-11-19
  • H5 js点击按钮复制文本到粘贴板

    H5 js点击按钮复制文本到粘贴板

    本文实例为大家分享了js点击按钮复制文本到粘贴板的具体代码,供大家参考,具体内容如下 准备:先去下载clipboard.js: 官网 移动端效果如下: 应用:html+js 代码
    2020-11-19
  • Android studio配置国内镜像源的实现

    Android studio配置国内镜像源的实现

    PS:网上看到的AS配置国内镜像源的博客版本有点老了,就想着做个比较新的博客了 推荐的几个国内镜像源地址: 1、东软信息学院(笔者当前在用) mirrors.neusoft.ed
    2020-11-19
  • JavaScript实现alert弹框效果

    JavaScript实现alert弹框效果

    本文实例为大家分享了JavaScript实现alert弹框的具体代码,供大家参考,具体内容如下 因本人水平有限,不足之处还望大家指正。 先上图: 为什么会出现这个需求?
    2020-11-19
  • C/C++宏替换实现详解

    C/C++宏替换实现详解

    基本形式 #define name replacement_text 通常情况下,#define 指令占一行,替换文本是 define 指令行尾部的所有剩余部分,但也可以把一个较长的宏定义分成若
    2020-11-19
  • Android Studio配置国内镜像源(利用hosts)

    Android Studio配置国内镜像源(利用hosts)

    之前我写过直接用国内镜像的IP地址端口进行配置国内镜像的,如下链接: Android studio配置国内镜像源 但是这种方法不一定在每台电脑上的每次配置都行得通,因
    2020-11-19
  • Android Studio实现简单音乐播放功能的示例代码

    Android Studio实现简单音乐播放功能的示例代码

    项目要求 基于Broadcast,BroadcastReceiver等与广播相关的知识实现简单的音乐播放功能,包括音乐的播放、暂停、切换、进度选择、音量调整。 设计效果 (进度条时间
    2020-11-19
  • docker 打包本地镜像,并到其他机器进行恢复操作

    docker 打包本地镜像,并到其他机器进行恢复操作

    1、使用docker images查看本机所有的镜像文件 2、docker save eb40dcf64078> /root/mydjango-save-1016.tar 将镜像保存为本地文件,其中eb40dcf64078为image id 3
    2020-11-19
  • Android Studio配置本地SDK的方法

    Android Studio配置本地SDK的方法

    Android Studio配置本地SDK 问题一:Android Studio报错:SDK does not contain any platforms. 解决方法:本地SDK应放到名为platforms的外层文件夹内。 例子
    2020-11-19

最新评论