读 .NET Core中的文件操作、读取文件、Debug/Trace 类、Conditional条件编译、CLS
- 1,文件操作
- 2,读取文件
- 3,Debug 、Trace类
- 4,条件编译
- 5,MethodImpl 特性
- 5,CLSCompliantAttribute
- 6,必要时自定义类型别名
目录:
1,文件操作
2,Debug、Trace类
3,条件编译
4,MethodImpl 特性
5,CLSComplianAttribute
6,必要时自定义类型别名
最近在阅读 .NET Core Runtime 的源码,参考大佬的代码,学习编写技巧和提高代码水平。学习过程中将学习心得和值得应用到项目中的代码片段记录下来,供日后查阅。
1,文件操作
这段代码在 System.Private.CoreLib 中。
有个读取文件转换为 byte[] 的方法如下:
public static byte[] ReadAllBytes(string path)
{
// bufferSize == 1 used to avoid unnecessary buffer in FileStream
using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 1))
{
long fileLength = fs.Length;
if (fileLength > int.MaxValue)
throw new IOException(SR.IO_FileTooLong2GB);
int index = 0;
int count = (int)fileLength;
byte[] bytes = new byte[count];
while (count > 0)
{
int n = fs.Read(bytes, index, count);
if (n == 0)
throw Error.GetEndOfFile();
index += n;
count -= n;
}
return bytes;
}
}
可以看到 FileStream 的使用,如果单纯是读取文件内容,可以参考里面的代码:
FileStream fs = new FileStream(path,
FileMode.Open,
FileAccess.Read,
FileShare.Read,
bufferSize: 1)
上面的代码同样也存在 File.ReadAllBytes 与之对应, File.ReadAllBytes 内部是使用 InternalReadAllBytes 来处理文档读取:
private static byte[] InternalReadAllBytes(String path, bool checkHost)
{
byte[] bytes;
// 此 FileStream 的构造函数不是 public ,开发者不能使用
using(FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read,
FileStream.DefaultBufferSize, FileOptions.None, Path.GetFileName(path), false, false, checkHost)) {
// Do a blocking read
int index = 0;
long fileLength = fs.Length;
if (fileLength > Int32.MaxValue)
throw new IOException(Environment.GetResourceString("IO.IO_FileTooLong2GB"));
int count = (int) fileLength;
bytes = new byte[count];
while(count > 0) {
int n = fs.Read(bytes, index, count);
if (n == 0)
__Error.EndOfFile();
index += n;
count -= n;
}
}
return bytes;
}
这段说明我们可以放心使用 File 静态类中的函数,因为里面已经处理好一些逻辑了,并且自动释放文件。
如果我们手动 new FileStream ,则要判断一些情况,以免使用时报错,最好参考一下上面的代码。
.NET 文件流缓存大小默认是 4096 字节:
internal const int DefaultBufferSize = 4096;
这段代码在 File 类中定义,开发者不能设置缓存块的大小,大多数情况下,4k 是最优的块大小。
ReadAllBytes 的文件大小上限是 2 GB。
3,Debug 、Trace类
#if 条件编译会隐藏非条件(#else if)代码,我们开发中很可能会忽略掉这部分代码,当我们切换条件常量到这部分代码时,很可能因为各种原因导致报错。
如果使用特性进行条件编译标记,在开发过程中就可以留意到这部分代码。
[Conditional("DEBUG")]
例如,当使用修改所有引用-修改一个类成员变量或者静态变量名称时,#if 非条件中的代码不会被修改,因为这部分代码“无效”,而且使用 [Conditional("DEBUG")] 的代码则跟条件无关,会被同步修改。
Conditional 特性标记的方法等,在开发过程中保持有效,当在编译时可能被排除。
代码片段只能使用 #if 了,如果是单个方法,则可以使用 Conditional 。
5,MethodImpl 特性
指示程序元素是否符合公共语言规范 (CLS)。
CLS规范可参考:
https://docs.microsoft.com/en-us/dotnet/standard/language-independence
https://www.ecma-international.org/publications/standards/Ecma-335.htm
全局开启方法:
程序目录下添加一个 AssemblyAttribytes.cs 文件,或者打开 obj 目录,找到 AssemblyAttributes.cs 结尾的文件,如 .NETCoreApp,Version=v3.1.AssemblyAttributes.cs,添加:
using System; // 这行已经有的话不要加
[assembly: CLSCompliant(true)]
之后就可以在代码中使用 [CLSCompliant(true)] 特性。
局部开启:
也可以放在类等成员上使用:
[assembly: CLSCompliant(true)]
您可以将特性应用于 CLSCompliantAttribute 下列程序元素:程序集、模块、类、结构、枚举、构造函数、方法、属性、字段、事件、接口、委托、参数和返回值。 但是,CLS 遵从性的概念仅适用于程序集、模块、类型和类型的成员。
程序编译时默认不会检查代码是否符合 CLS 要求,但是如果你的可以是公开的(代码共享、Nuget 发布等),则建议使用使用 [assembly: CLSCompliant(true)] ,指明你的库符合 CLS 要求。
在团队开发中以及内部共享代码时,高质量的代码尤为重要,所以有必要使用工具检查代码,如 roslyn 静态分析、sonar 扫描等,也可以使用上面的特性,自动使用 CLS 检查。
CLS 部分要求:
-
无符号类型不应成为该类的公共接口的一部分(私有成员可以使用),例如 UInt32 这些属于 C# 的类型,但不是 CLS “标准” 中的。
-
指针等不安全类型不能与公共成员一起使用,就是公有方法中都不应该使用 unsafe 代码。(私有成员可以使用)。
-
类名和成员名不应重名。虽然 C# 中区分大小写,但是 CLS 不建议同名非重载函数,例如 MYTEST 跟 Mytest。
-
只能重载属性和方法,不应重载运算符。重载运算符容易导致调用者不知情时出现程序错误,并且重载运算符要排查问题十分困难。
我们可以编译以下代码,尝试使用 CLSCompliant :
[assembly: CLSCompliant(true)]
[CLSCompliant(true)]
public class Test
{
public void MyMethod()
{
}
public void MYMETHOD()
{
}
}
IDE 中会警告:warning CS3005: 仅大小写不同的标识符“Test.MYMETHOD()”不符合 CLS,编译时也会提示 Warn。当然,不会阻止编译,也不会影响程序运行。
总之,如果要标记一个程序集 CLS 规范,可以使用 [assembly: CLSCompliant(true)] 特性。
[CLSCompliant(true)] 特性指示这个元素符合 CLS 规范,这时编译器或者 IDE 会检查你的代码,检查是否真的符合规范。
如果偏偏要写不符合规范的代码,则可以使用 [CLSCompliant(false)]。
6,必要时自定义类型别名
C# 也可以定义类型别名。
using intbyte = System.Int32;
using intkb = System.Int32;
using intmb = System.Int32;
using intgb = System.Int32;
using inttb = System.Int32;
byte[] fileByte = File.ReadAllBytes("./666.txt");
intmb size = fileByte.Length / 1024;
一些情况下,使用别名可以提高代码可读性。真实项目不要使用以上代码,我只是写个示例,这并不是合适的应用场景。
今天学习 Runtime 的代码就到这里为止。
==
出处:https://www.cnblogs.com/whuanle/p/14141213.html