C#的基础
一:Ref和Out 的区别:
1、使用ref型参数时,传入的参数必须先被初始化。对out而言,必须在方法中对其完成初始化。
2、使用ref和out时,在方法的参数和执行方法时,都要加Ref或Out关键字。以满足匹配。
3、out适合用在需要retrun多个返回值的地方,而ref则用在需要被调用的方法修改调用者的引用的时候。
4、ref是有进有出,而out是只出不进。
二:装箱和拆箱
在应用中最大的一个意义就在于:理解数据从栈移动到堆的过程中所发生的性能消耗问题,反之亦然。
考虑一下以下的代码片段,当我们将一个值类型转换为引用类型,数据将会从栈移动到堆中。相反,当我们将一个引用类型转换为值类型时,数据也会从堆移动到栈中。
不管是在从栈移动到堆还是从堆中移动到栈上都会不可避免地对系统性能产生一些影响。
于是,两个新名词横空出世:当数据从值类型转换为引用类型的过程被称为“装箱”,而从引用类型转换为值类型的过程则被成为“拆箱”。
如果你编译一下上面这段代码并且在ILDASM(一个IL的反编译工具)中对其进行查看,你会发现在IL代码中,装箱和拆箱是什么样子的。下图则展示了示例代码被编译后所产生的IL代码。
装箱和拆箱的性能问题
为了弄明白到底装箱和拆箱会带来怎样的性能影响,我们分别循环运行10000次下图所示的两个函数方法。其中第一个方法中有装箱操作,另一个则没有。我们使用一个Stopwatch对象来监视时间的消耗。
具有装箱操作的方法花费了3542毫秒来执行完成,而没有装箱操作的方法只花费了2477毫秒,整整相差了1秒多。而且,这个值也会因为循环次 数的增加而增加。也就是说,我们要尽量避免装箱和拆箱操作。在一个项目中,如果你需要装箱和装箱,请仔细考虑它是否是绝对必不可少的操作,如果不是,那么 尽量不用。
虽然以上代码段没有展示拆箱操作,但其效果同样适用于拆箱。你可以通过写代码来实现拆箱,并且通过Stopwatch来测试其时间消耗。
五: 获取程序当前路径
有很多方法能够获取程序当前路径
- 获取当前 Thread 的当前应用程序域的基目录,它由程序集冲突解决程序用来探测程序集。(推荐使用这种方式)
string str = System.AppDomain.CurrentDomain.BaseDirectory;
返回结果:
X:\xxx\xxx\ (.exe文件所在的目录+”\”)
- 获取新的 Process 组件并将其与当前活动的进程关联的主模块的完整路径,包含文件名(进程名)。
string str = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
返回结果:
X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
- 获取和设置当前目录(即该进程从中启动的目录)的完全限定路径。
string str = System.Environment.CurrentDirectory;
返回结果:
X:\xxx\xxx (.exe文件所在的目录)
- 获取和设置包含该应用程序的目录的名称。
string str = System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
返回结果:
X:\xxx\xxx\ (.exe文件所在的目录+”\”)
- 获取应用程序的当前工作目录(不可靠)。
string str = System.IO.Directory.GetCurrentDirectory();
返回结果:
X:\xxx\xxx (.exe文件所在的目录)
- 获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称。(仅限WinForm程序)
string str = System.Windows.Forms.Application.StartupPath;
返回结果:
X:\xxx\xxx (.exe文件所在的目录)
- 获取启动了应用程序的可执行文件的路径,包括可执行文件的名称。(仅限WinForm程序)
string str = System.Windows.Forms.Application.ExecutablePath;
返回结果:
X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
- 获取包含清单的已加载文件的路径或 UNC 位置。
public static string sApplicationPath = Assembly.GetExecutingAssembly ( ).Location;
返回结果:
X:\xxx\xxx\xxx.dll (.dll文件所在的目录+.dll文件名)
- 获取当前进程的完整路径,包含文件名(进程名)。
string str = this.GetType ( ).Assembly.Location;
返回结果:
X:\xxx\xxx\xxx.exe (.exe文件所在的目录+.exe文件名)
六:读写程序配置文件
程序配置文件作为程序重要配置信息文件,在项目开发过程中,我们可能需要对其进行读写操作。
配置文件在不同类型的项目中,名称不同:
- Web项目配置文件为:web.config
- WinForm项目配置文件为:app.config
.Net Framework为我们提供了相应类进行程序配置文件操作。
在配置文件中,有几个节点是可以进行自定的:
- appSettings:程序设置,key-value键值对信息
- connectionStrings:连接字符串
appSettins读写操作
配置文件内容格式:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="DemoKey" value="*" />
</appSettings>
</configuration>
读:
String str = ConfigurationManager.AppSettings["DemoKey"];
写:
Configuration cfa = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
cfa.AppSettings.Settings.Add("key", "Name")||cfa.AppSettings.Settings["key"].Value = "name";
cfa.Save();
注意:调用ConfiguionManager必须要先在工程里添加system.configuration.dll程序集的引用。
connectionStrings读写操作
获取ConnectionStrings配置节中的值
//// <summary>
/// 获取ConnectionStrings配置节中的值
/// </summary>
/// <returns></returns>
public static string GetConnectionStringsElementValue()
{
ConnectionStringSettings settings = System.Configuration.ConfigurationManager.ConnectionStrings["connectionString"];
return settings.ConnectionString;
}
保存值
//// <summary>
/// 保存节点中ConnectionStrings的子节点配置项的值
/// </summary>
/// <param name="elementValue"></param>
public static void ConnectionStringsSave(string ConnectionStringsName, string elementValue)
{
System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
config.ConnectionStrings.ConnectionStrings["connectionString"].ConnectionString = elementValue; config.Save(ConfigurationSaveMode.Modified);
ConfigurationManager.RefreshSection("connectionStrings");
}
八:常用的Stream和Byte[]操作
Stream和Byte[]是C#中比较底层的操作,直接针对文件内容进行操作,所以掌握常用的操作,能增强我们开发技能。
转换操作
Stream 和 byte[] 之间的转换
将 Stream 转成 byte[]
public byte[] StreamToBytes(Stream stream)
{
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
// 设置当前流的位置为流的开始
stream.Seek(0, SeekOrigin.Begin);
return bytes;
}
将 byte[] 转成 Stream
public Stream BytesToStream(byte[] bytes)
{
Stream stream = new MemoryStream(bytes);
return stream;
}
byte[]与string的转换代码
将string转换为byte[]
System.Text.UnicodeEncoding converter = new System.Text.UnicodeEncoding();
byte[] inputBytes =converter.GetBytes(inputString);
string inputString = converter.GetString(inputBytes);
将byte[]转换为string
string inputString = System.Convert.ToBase64String(inputBytes);
byte[] inputBytes = System.Convert.FromBase64String(inputString);
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
Stream 和 文件之间的转换
将 Stream 写入文件
public void StreamToFile(Stream stream,string fileName)
{
// 把 Stream 转换成 byte[]
byte[] bytes = new byte[stream.Length];
stream.Read(bytes, 0, bytes.Length);
// 设置当前流的位置为流的开始
stream.Seek(0, SeekOrigin.Begin);
// 把 byte[] 写入文件
FileStream fs = new FileStream(fileName, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(bytes);
bw.Close();
fs.Close();
}
从文件读取 Stream
public Stream FileToStream(string fileName)
{
// 打开文件
FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
// 读取文件的 byte[]
byte[] bytes = new byte[fileStream.Length];
fileStream.Read(bytes, 0, bytes.Length);
fileStream.Close();
// 把 byte[] 转换成 Stream
Stream stream = new MemoryStream(bytes);
return stream;
}
图片和byte[]互相转换
二进制转换成图片
MemoryStream ms = new MemoryStream(bytes);
ms.Position = 0;
Image img = Image.FromStream(ms);
ms.Close();
this.pictureBox1.Image
图片转二进制
Bitmap BitReturn = new Bitmap();
byte[] bReturn = null;
MemoryStream ms = new MemoryStream();
BitReturn.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
bReturn = ms.GetBuffer();