给 c# 程序员的十个重要提示
给 c# 程序员的十个重要提示
本文讲述我认为对 c# 程序员最重要的 10 个提示, 每个提示都会有一段对应的代码, 对 新手来说也很容易掌握。
1: 为非公开的方法编写测试
你尝试过为组件的非公开方法写测试么? 很多开发者都没有写过, 因为这些方法对测试项 目来说是不可见的。 c# 可以通过在 AssemblyInfo.cs
中添加下面的标记 (InternalsVisibleToAttribute
) , 让内部成员对其它组件可见。
//Make the internals visible to the test assembly
[assembly: InternalsVisibleTo("MyTestAssembly")]
2: 使用 Tuples 类型
曾经见到过有人仅仅因为函数要返回多个值而创建了一个 POCO 类, 其实 .Net 4.0 中的 Tuples
类型会更加适用, 例如:
public Tuple<int, string, string> GetEmployee() {
int employeeId = 1001;
string firstName = "Rudy";
string lastName = "Koertson";
//Create a tuple and return
return Tuple.Create(employeeId, firstName, lastName);
}
3: 用 yield 替代临时集合
从集合中选出部分成员时, 通常会创建一个临时集合/列表来保存成员并返回, 例如下面 的代码:
public List<int> GetValuesGreaterThan100(List<int> masterCollection) {
List<int> tempResult = new List<int>();
foreach (var value in masterCollection) {
if (value > 100) {
tempResult.Add(value);
}
}
return tempResult;
}
要避免这样的临时集合, 可以使用 yield
关键字, 示例如下:
public IEnumerable<int> GetValuesGreaterThan100(List<int> masterCollection) {
foreach (var value in masterCollection) {
if (value > 100) {
yield return value;
}
}
}
当然, 也可是使用 LINQ 来解决上面的问题。
4: 告诉别人你将替换一个方法
当你有一个组件时, 并且你打算替换其中的一个方法时, 可以先为方法添加过时标记以通 知客户端, 示例代码如下:
[Obsolete("This method will be deprecated soon. You could use XYZ alternatively.")]
public void MyComponentLegacyMethod() {
//Here is the implementation
}
使用这个方法客户端在编译时会发出一个警告, 如果你不再允许客户端使用过时的方法时, 可以为过时标记添加一个额外的布尔参数, 在下面的例子中, 客户但程序将编译失败:
[Obsolete("This method is deprecated. You could use XYZ alternatively.", true)]
public void MyComponentLegacyMethod() {
//Here is the implementation
}
5: 牢记 LINQ 查询是延迟执行的
在 .NET 中编写 LINQ 查询时, 只有当你访问 LINQ 查询的结果时, LINQ 查询才会被执 行, LINQ 的这种特征被称为延迟执行, 不过值得注意的是每访问一次结果, LINQ 查询 都会被执行一次。
为了避免重复 LINQ 查询的重复执行, 可以先将查询转换成列表, 如下所示:
public void MyComponentLegacyMethod(List<int> masterCollection) {
// 在下面示例中, 如果没有调用 ToList , LINQ 查询将会被执行两次
var result = masterCollection.Where(i => i > 100).ToList();
Console.WriteLine(result.Count());
Console.WriteLine(result.Average());
}
6: 使用 explicit 关键字转换业务实体类型
使用 explicit
关键字来定义业务实体类型之间的转换, 当代码中出现类型转换请求时, 转换方法会自动执行, 下面是示例代码:
class Program {
static void Main(string[] args) {
var entity = new ExternalEntity {
Id = 1001,
FirstName = "Dave",
LastName = "Johnson"
};
var convertedEntity = (MyEntity)entity;
}
}
class MyEntity {
public int Id { get; set; }
public string FullName { get; set; }
public static explicit operator MyEntity(ExternalEntity externalEntity) {
return new MyEntity {
Id = externalEntity.Id,
FullName = externalEntity.FirstName + " " + externalEntity.LastName
};
}
}
class ExternalEntity {
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
7: 保持异常的原始堆栈跟踪
在 c# 代码中, 如果你像下面的代码一样在 catch
代码块中抛出 ConnectDatabase
方法中出现的异常, 异常的堆栈就会只显示到 RunDataOperation
方法, 这样就会丢失 异常原始的堆栈跟踪信息导致不能找到确切的错误源头。
public void RunDataOperation() {
try {
Intialize();
ConnectDatabase();
Execute();
}
catch (Exception exception) {
throw exception;
}
}
保持原始堆栈跟踪的代码如下:
public void RunDataOperation() {
try {
Intialize();
ConnectDatabase();
Execute();
}
catch (Exception) {
throw;
}
}
8: 使用 Flags 标记将枚举作为位域处理
在 c# 中为枚举类型添加 Flags
标记可以将枚举作为位域(即一组标志)处理, 这样可 以对枚举值进行自由组合, 示例代码如下:
class Program {
static void Main(string[] args) {
int snakes = 14;
Console.WriteLine((Reptile)snakes);
}
}
[Flags]
enum Reptile {
BlackMamba = 2,
CottonMouth = 4,
Wiper = 8,
Crocodile = 16,
Aligator = 32
}
上面代码的输出为 “BlackMamba, CottonMouth, Wiper” , 如果没有 Flags 标记, 则上 面的输出为 14 。
9: 为泛型添加类型约束
创建泛型类型时, 需要指定提供的泛型类型必须实现指定的参数或者继承自特定的基类时, 可以这样做:
class MyGenricClass<T> where T : IMyInterface {
//Body of the class come in here
}
当然, 也可以在方法级别这样做:
class MyGenricClass {
public void MyGenericMethod<T>(T t) where T : IMyInterface {
//Generic implementation goes in here
}
}
10: IEnumerable 类型不能确保只读
在你创建的类型中, 暴露了一个类型为 IEnumerable
的只读属性, 但是调用者依然可 以通过类型转换来修改属性的内容, 比如这样:
class Program {
static void Main(string[] args) {
MyClass myClass = new MyClass();
((List<string>)myClass.ReadOnlyNameCollection).Add("######From Client#####");
myClass.Print();
}
}
class MyClass {
List<string> _nameCollection = new List<string>();
public MyClass() {
_nameCollection.Add("Rob");
_nameCollection.Add("John");
_nameCollection.Add("Jummy");
_nameCollection.Add("Derek");
}
public IEnumerable<string> ReadOnlyNameCollection {
get { return _nameCollection.AsEnumerable(); }
}
public void Print() {
foreach (var item in ReadOnlyNameCollection) {
Console.WriteLine(item);
}
}
}
上面的代码修改了列表, 添加了一个新项目, 要避免这种情况, 应使用 AsReadOnly
而不是 AsEnumerable
:
public IEnumerable<string> ReadOnlyNameCollection {
get { return _nameCollection.AsReadOnly(); }
}
希望这些提示对你有用!
原文地址: Top 10 Tips for C# Programmers
iOS 中的 CFBundleShortVersionString 与 CFBundleVersion
Xamarin Studio 比 Visual Studio 2013 好用的三个功能
- 有了phonegap你还android吗?
- zookeeper学习系列:三、利用zookeeper做选举和锁
- Spring Cloud构建微服务架构:分布式服务跟踪(收集原理)【Dalston版】
- zookeeper学习系列:二、api实践
- Spring Cloud构建微服务架构:分布式服务跟踪(整合logstash)【Dalston版】
- Spring Cloud构建微服务架构:分布式服务跟踪(整合zipkin)【Dalston版】
- 困扰我多年的Connection reset问题
- scala学习笔记
- jersey处理支付宝异步回调通知的问题:java.lang.IllegalArgumentException: Error parsing media type 'application/x-www
- 使用 Java Service Wrapper 启动java后台进程服务
- PHP码农在Golang压力下的生存之道-PHP性能优化实践
- golang使用 mongo
- CoreOS Linux引入了Kubernetes kubelet
- gwt之mvc4g
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Ant-design-vue+vue-i18n实现前端国际化
- Mac OSX终端安装主题(oh my zsh)
- 谷歌浏览器油猴插件安装教程,让你的浏览器更加强大
- zabbix模块配置学习
- Windows下安装及使用NVM
- U盘上安装多个Linux发行版和PE
- ubuntu18.04部署python3、nginx项目
- CentOS8.x系统配置记录
- js根据经纬度换算行驶里程
- ubuntu18.04 安装docker
- COBBLER无人值守批量安装系统.md
- 使用VSCode 打包你的第一个flutter应用(安卓篇)
- KICKSTART无人值守批量安装系统.md
- Centos7-Firewall防火墙基础讲解
- 优酷iOS插件化页面架构方法