🎬 博客主页:https://xiaoy.blog.csdn.net
🎥 本文由 呆呆敲代码的小Y 原创,首发于 CSDN🙉
🎄 学习专栏推荐:Unity精品学习专栏
🌲 游戏制作专栏推荐:游戏制作分享
🌲Unity实战100例专栏推荐:Unity 实战100例 教程
🏅 欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📆 未来很长,值得我们全力奔赴更美好的生活✨
------------------❤️分割线❤️-----------------------
在我们程序员日常开发的过程中,会编写代码是一个最基本且常规的操作。
而作为一名合格的软件工程师
,出产物就应该具备工程的健壮性
和美观性
,因此编码规范是作为软件工程师的职业素养。
但是就 编码规范
而言,可能大多数程序员都是按照自己的长久习惯进行代码编写,并没有遵循一个约定好的编码规范。
所以本篇就来对C#中的编码规范
做一个详细的总结整理,并对一些超级常用的做一个重点解析!
对于编程而言,大多数语言的编码规范基本上是遵循一些相同的规范标准的,除去少些个语言有一些特殊用法之外。
所以本篇文章不止对使用C#工程师们有帮助哦,不使用C#的小伙伴也可以看看跟自己平时用的语言有什么编码差异吧!
- Coding standards are collections of rules and guidelines that determine the programming style, procedures, and methods for a programming language.
- Think of coding standards as a set of rules, techniques, and best practices to create cleaner, more readable, more efficient code with minimal errors. They offer a uniform format by which software engineers can use to build sophisticated and highly functional code.
- 编码规范是针对某种编程语言的,决定编程风格、过程和方法的一系列规则和指导方针的集合。
- 把编码规范看作是一套规则、技术和最佳实践,以创建更清爽、更可读、更有效的代码,并将错误降到最低。它们提供了一个统一的格式,软件工程师可以用它来构建复杂和功能强大的代码。
软件工程师
,出产物就应该具备工程的健壮性和美观性,因此编码规范是作为软件工程师的职业素养。初学者
来说,可能对这方面并没有重视起来,还是依据自己的想法对变量
和方法
等等随意命名。如果没有编码规范,团队中的每个人都按自己的编码风格来。在不久的将来,维护和调试代码将变得不容易。
有一套编码标准在手,更容易保持代码的清晰和易于协作。当然,标准因应用、性质、行业、项目、开发人员技能和多种因素而不同。
对于一个开发团队来说,在开发过程中拥有适当的编码规范和标准是至关重要的,这将有助于团队保持代码质量,并减少新的开发人员试图理解复杂的代码库所花费的时间。
C# 的命名有两种约定:帕斯卡拼写法(Pascal) 和 驼峰命名法(camelCasing)
帕斯卡拼写法(Pascal):
成员名的每个单词的首位字母大写,如:Student,StudentName,StudentParentName。驼峰命名法(camelCasing)
:成员名除了第一个单词外其余首字母都大写,Student,studentName,studentParentName.1.class
、record
及record的参数
、struct
的名称,如:
public class DataService
{
}
public record PhysicalAddress(
string Street,
string City,
string StateOrProvince,
string ZipCode);
public struct ValueCoordinate
{
}
2.命名 interface
时,使用 pascal
大小写并在名称前面加上前缀 I
。 这可以清楚地向使用者表明这是 interface。
public interface IWorkerQueue
{
}
3.public
的成员也应为Pascal
命名,这些成员包括字段、属性、事件。
方法名也应遵循Pascal命名,无论其是否是public。如:
public class ExampleEvents
{
//公共字段
public bool IsValid;
//公共属性
public IWorkQueue WorkQueue{get;set;}
//公共事件
public event Action EventProcessing;
//公共方法
public void Run()
{
}
}
4.编写位置记录时,对参数使用 pascal 大小写,因为它们是记录的公共属性。
public record PhysicalAddress(
string Street,
string City,
string StateOrProvince,
string ZipCode);
1.命名private
或internal
字段时使用驼峰命名,且字段名应以_
开头。如:
public class DataService
{
private IWorkerQueue _workerQueue;
}
2.如果是static
的private
或internal
的字段,则字段名应该以s_
开头,对于线程静态则应该使用t_
开头。如:
public class DataService
{
private static IWorkerQueue s_workerQueue;
[ThreadStatic]
private static TimeSpan t_timeSpan;
}
3.编写方法的参数名时,也应该以驼峰命名,如:
public T SomeMethod<T>(int someNumber, bool isValid)
{
}
using
指令的示例中,使用命名空间限定。如果你知道命名空间默认导入项目中,则不必完全限定来自该命名空间的名称。 如果对于单行来说过长,则可以在点 (.) 后中断限定名称,如下面的示例所示。
var currentPerformanceCounterCategory = new System.Diagnostics.
PerformanceCounterCategory();
不必更改使用 Visual Studio 设计器工具创建的对象的名称以使它们适合其他准则。
私有成员
可以使用下划线_
开始常量
命名全部大写,单词间用下划线隔开,力求语意表达完整清楚,不要嫌名字长。正例:MAX_XIAOY_COUNT
反例:MAX_xiaoy_COUNT
抽象类
命名使用 Abstract或Base开头;异常类命名使用Exception结尾;测试类命名以它要测试的类名称开始,以Test结尾。 ///
/// 抽象类命名
///
public void AbstractLearnProgramming()
{
}
///
/// 异常类命名
///
public void LearnProgrammingException()
{
}
///
/// 测试类命名
///
public void LearnProgrammingTest()
{
}
设计模式
,建议在类名中体现出具体模式。说明:将设计模式体现在名字中,有利于阅读者快速理解架构设计思想。
例如:
public class SysuserController
public class OrderFactory
public class TcpProxy
枚举
类名建议带上E前缀或Enum后缀,枚举成员名称需要全大写,单词间用下滑线隔开。说明:枚举其实就是特殊的常量类i,切构造方法被默认强制是私有。
正例:枚举名字:EState / DealStatusEnum
成员名:SUCCESS / UNKOWN_REASON
1.使用默认的代码编辑器设置(智能缩进、4 字符缩进、制表符保存为空格)。
2.每行只写一条语句。
//正确
int age = 20;
int score = 90;
//错误示范
int age = 20; int score = 90;
3.每行只写一个声明。
4.C# 的大括号采用的是Allman style,大括号单独一行。以下是正确的:
///
/// 正确示范
///
public void StartGame()
{
}
///
/// 错误示范
///
public void StartGame(){
}
5.如果连续行未自动缩进,请将它们缩进一个制表符位(四个空格)。
6.在方法定义与属性定义之间添加至少一个空白行。
public string Name { get; set; }
public void StartGame()
{
}
7.使用括号突出表达式中的子句,如下面的代码所示。
if ((val1 > val2) && (val1 > val3))
{
// Take appropriate action.
}
8.if / for / while / switch / do
等保留字与左右括号之间都必须加空格。
9.任何运算符左右必须加一个空格。
说明:运算符包括赋值运算符 = 、逻辑运算符&&、加减乘除符号、三目运算符等。
10.方法参数在定义和传入时,多个参数逗号后必须加空格。
正例:下例中实参的 ” a ” ,后边必须要有一个空格。
XIaoYMethod("a", "b", "c");
1.将注释放在单独的行上,而非代码行的末尾。
正确示范
// 定义age并初始化. Define age and init.
int age = 20;
错误示范
int age = 20;//定义age并初始化
2.类方法的注释必须使用C# Summary 规范,以大写字母开始注释文本。
///
/// Start the text with a capital letter.
///
public void StartGame()
{
}
说明:在vs中,Summary方式会提示相关的注释,生成Summary可以正确输出相应的注释。工程调用方法是,不进入方法,即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
3.以句点结束注释文本。
4.在注释分隔符 (//) 与注释文本之间插入一个空格,如下面的示例所示。
// The following declaration creates a query. It does not run
// the query.
5.请勿在注释周围创建格式化的星号块。
6.请确保所有公共成员Public都有必要的注释,从而提供有关其行为的适当说明。
7.所有的抽象方法(包括接口中的方法)必须使用Summary
注释,除了返回值、参数、异常说明外,还必须指出该方法做了什么事,实现了什么功能。
说明:对于子类的实现要求,或者调用注意事项,请一并说明。
8.方法内部单行注释,在被注释语句上方另起一行,使用 //
注释。方法内部多行注释使用 /* */
注释,注意与代码对齐。
9.语气 “ 半吊子 ” 英文来注释,不如用中文注释把问题说清楚。但专有名字与关键字保持英文原文即可。
反例: “ TCP连接超时 ” 解释成 “ 传输控制协议连接超时 ” ,理解反而费脑筋。
10.代码修改的同事,注释也要进行相应的修改,预期是参数、返回值、异常、核心逻辑等的修改。
11.注释掉的代码尽可能而配合说明,而不是简单的注释掉
说明:代码被注释掉有两种可能性:
12.对于注释的要求:
完全没有注释的大段代码,对于阅读者形同天书,注释是给自己看的,即使隔很长时间,也能够清晰理解当时的思路;
注释也是给继任者看的,使其能够快读接替自己的工作。
13.好的命名、代码结构是自解释的,注释力求精简准确,表达到位。
避免出现注释的一个极端:过多滥的注释,代码逻辑一旦修改,修改注释是相当大的负担。
14.特殊注释标记,请注明标记人与标记时间。
注意及时处理这些标记,通过标记扫描,经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
1)待办事宜(TODO):(标记人、标记时间,[预计处理时间])表示需要实现,但目前还未实现的功能。
字符串内插
来连接短字符串,如下面的代码所示。string displayName = $"{nameList[n].LastName}, {nameList[n].FirstName}";
StringBuilder
对象。var phrase = "xiaoYxiaoYxiaoYxiaoYxiaoYxiaoY";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
隐式类型化
。var var1 = "This is clearly a string.";
var var2 = 27;
var
。 请勿假设类型明显来自方法名称。 如果变量类型为 new 运算符或显式强制转换,则将其视为明显来自方法名称。int var3 = Convert.ToInt32(Console.ReadLine());
int var4 = ExampleClass.ResultSoFar();
inputInt
会产生误导性。 它是字符串。var inputInt = Console.ReadLine();
Console.WriteLine(inputInt);
for
循环中循环变量的类型。var phrase = "xiaoYxiaoYxiaoYxiaoYxiaoYxiaoY";
var manyPhrases = new StringBuilder();
for (var i = 0; i < 10000; i++)
{
manyPhrases.Append(phrase);
}
//Console.WriteLine("tra" + manyPhrases);
foreach
循环中循环变量的类型。 在大多数情况下,集合中的元素类型并不明显。 不应仅依靠集合的名称来推断其元素的类型。下面的示例在 foreach
语句中使用显式类型化。
foreach (char ch in laugh)
{
if (ch == 'h')
Console.Write("H");
else
Console.Write(ch);
}
Console.WriteLine();
通常,使用 int
而非无符号类型。 int
的使用在整个 C# 中都很常见,并且当你使用 int 时,更易于与其他库交互。
当在声明行上初始化数组时,请使用简洁的语法。 在以下示例中,请注意不能使用 var
替代 string[]
。
string[] xiaoY = { "x", "i", "a", "o", "Y" };
如果使用显式实例化,则可以使用 var
。
var xiaoY = new string[] { "x", "i", "a", "o", "Y" };
在用到委托时尽量使用 Func<>
和 Action<>
,而不是自定义委托类型。 在类中,定义委托方法。
public static Action<string> ActionExample1 = x => Console.WriteLine($"x is: {x}");
public static Action<string, string> ActionExample2 = (x, y) =>
Console.WriteLine($"x is: {x}, y is {y}");
public static Action<string> ActionExample3 = X;
static void X(string s)
{
Console.WriteLine($"x is: {s}");
}
public static Func<string, int> FuncExample1 = x => Convert.ToInt32(x);
public static Func<int, int, int> FuncExample2 = (x, y) => x + y;
如果创建委托类型的实例,请使用简洁的语法。 在类中,定义委托类型和具有匹配签名的方法。
public delegate void Del(string message);
public static void DelMethod(string str)
{
Console.WriteLine("DelMethod argument: {0}", str);
}
创建委托类型的实例,然后调用该实例。 以下声明显示了紧缩的语法。
Del exampleDel2 = DelMethod;
exampleDel2("Hey xiaoY");
以下声明使用了完整的语法。
Del exampleDel1 = new Del(DelMethod);
exampleDel1("Hey xiaoY");
1.try-catch 和 using 语句正在异常处理中
在平时使用异常处理时一般都使用 try-catch
语句。我们可以使用 using
来简化代码,简化资源的Dispose
。
如果具有 try-finally
语句(该语句中 finally 块的唯一代码是对 Dispose 方法的调用),可使用 using 语句代替。
如:
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
{
((IDisposable)font1).Dispose();
}
}
可使用using简化为:
using (Font font2 = new Font("Arial", 10.0f))
{
byte charset2 = font2.GdiCharSet;
}
在C# 8中可以进一步简化:
using Font font3 = new Font("Arial", 10.0f);
byte charset3 = font3.GdiCharSet;
2.异常不要用来做流程控制,条件控制。因为异常的处理效率比条件分支低。
3.大段代码进行try-catch,这是不负责任的表现。catch时请分清稳定代码合肥稳定代码,稳定代码指的是无论如何都不会出错的代码。对于费稳定代码的catch尽量可能的进行区分异常类型,再做对应的异常处理。
4.捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,就将该异常抛给他的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容。
5.有try块放到了事务代码中,catch异常后,如果要回滚事务,一定要注意手动回滚事务。
6.finally块必须对资源对象、流对象进行关闭,有异常也要做tyr-catch。
7.捕获异常与抛异常,必须是完全匹配,或者捕获异常是抛异常的父类。
说明:如果预期对方抛的是绣球,实际接到的是铅球,就会产生意外情况。
8.方法的返回值可以是null,不强制返回空集合或空对象等,必须添加注释充分说明什么情况下会返回null值。调用方进行null判断,防止NRE空引用异常问题(NullReferenceException)。
若要通过跳过不必要的比较来避免异常并提高性能,请在执行比较时使用 &&
(而不是 &)和 ||
(而不是 |),如下面的示例所示。
Console.Write("Enter a dividend: ");
int dividend = Convert.ToInt32(Console.ReadLine());
Console.Write("Enter a divisor: ");
int divisor = Convert.ToInt32(Console.ReadLine());
if ((divisor != 0) && (dividend / divisor > 0))
{
Console.WriteLine("Quotient: {0}", dividend / divisor);
}
else
{
Console.WriteLine("Attempted division by 0 ends up here.");
}
如果除数为 0,则 if 语句中的第二个子句将导致运行时错误。
但是,当第一个表达式为 false 时,&&
运算符将发生短路。 也就是说,它并不评估第二个表达式。 如果 divisor 为 0,则 &
运算符将同时计算这两个表达式,这会导致运行时错误。
使用对象初始值设定项简化对象创建,如以下示例中所示。
var student1 = new ExampleClass { Name = "xioaY", ID = 001,
sex = "man", Age = 24 };
下面的示例设置了与前面的示例相同的属性,但未使用初始值设定项。不建议使用
var student2 = new ExampleClass();
student2.Name = "xiaoYY";
student2.ID = 002;
student2.sex = "man";
student2.Age = 20;
如果正在定义一个稍后不需要删除的事件处理程序,请使用 lambda
表达式。
public Form1()
{
this.Click += (s, e) =>
{
MessageBox.Show(
((MouseEventArgs)e).Location.ToString());
};
}
Lambda
表达式缩短了以下传统定义。
public Form1()
{
this.Click += new EventHandler(Form1_Click);
}
void Form1_Click(object? sender, EventArgs e)
{
MessageBox.Show(((MouseEventArgs)e).Location.ToString());
}
使用类名调用 static
成员:ClassName.StaticMember
。
这种做法通过明确静态访问使代码更易于阅读。 请勿使用派生类的名称来限定基类中定义的静态成员。
编译该代码时,代码可读性具有误导性,如果向派生类添加具有相同名称的静态成员,代码可能会被破坏。
1.避免通过一个类的对象引用访问此类的静态变量或静态方法,无谓增加编译器解析成本,直接用类名来访问即可
2.不能使用过时的类或方法([Obsolate]标识
)
说明:C#中对于标记过时的方法,有可能会在新版本的.Net Framework
中剔除,因此不建议继续使用此类或方法。
3.Object 的Equals
方法容易抛空引用异常,应使用常量或确定有值得对象来调用Equals。
//反例
"XiaoY".Equals(gameObject.tag);
//正例
gameObject.tag.Equals("XiaoY");
4.构造方法
中禁止加入业务逻辑,如有初始化逻辑等,请放在Init() 方法中。
5.当一个类有多个构造方法,或多个同名方法,这些方法应该按照顺序放置在一起,便于阅读。
6.类内方法定义顺序依次是:常量、字段、属性、方法,按照public -> protected -> private 排序。
7.类成员与方法访问控制从严
说明:任何类、方法、参数、变量,严控访问范围,过宽泛的访问范围,不利于模块解耦。如果一个private的方法,想删除就删除,可是一个public的Service方法,或者一个public的成员变量,删除一下,造成的损失可能没办法完全掌控。所以在一开始创建该类时就应该将访问明码标价,防止后期出现其他问题。
1.在一个switch块内,每个case要么通过break/return等来终止,要么注释说明程序将继续执行到哪一个case为止:在一个switch块内,都必须包含一个default语句,并且放在最后,即使它什么代码都没有。
2.在 if / else / for / while / do 语句中都必须使用大括号,即使只有一行代码,避免使用下面的形式: if (condition) do something…
3.循环体内的语句要考虑性能,以下操作尽量移至循环体外处理,如定义对象、变量、获取数据库连接
最后在评论区进行抽取三名 送出优质评论的幸运小伙伴
送下面这本书籍
博主这有一些Unity相关的书籍,是由 清华大学出版社 赞助的,在此感谢~大家喜欢的也可以去官方购买!
在这里搞个小活动抽奖送给大家,对看书感兴趣的小伙伴可以参加一波呀,刚开始可能参与的不多,抽中概率很大哦!
《Unity游戏优化(第三版)》
一本非常经典的Unity编程宝典,可以迅速提高编程水平!
尤其是想从事Unity开发的小伙伴,这本书就可以让你了解相关知识,对症下药可以极大地提高学习效率!
🎁抽奖规则
规则如下:
🚀 规则如下🚀 |
点赞 收藏 评论
三连,然后在评论区评论里 送一本书籍,总共抽三本!抽三本
,中的几率还是很大的哦~ 想看书的小伙伴参与起来!中奖信息
本周日下午本篇文章评论区公布!记得留意呀!🚀 规则如上🚀 |
🎄《《Unity游戏优化(第三版)》推荐理由(⭐⭐⭐⭐⭐)
图书简介
书本图片如下,喜欢的小伙伴参与起来!也可以京东链接自行购买哦~
喜欢的小伙伴可以尝试抽奖一下呀!
抽不到的小伙伴喜欢的也可以自行购买哦,这本书还是很不错的!