1.昨晚在对一个Array做处理的时候,为了删除一个元素,写出了如代码段1非常臃肿的代码:
//代码段1
bool isFind = false; //内存对象里是否包含待删除元素
foreach (FilesFile tempFile in contentInMemory.Items)
{
if (tempFile.Digest != file.Digest)
{
newArray[count] = tempFile;
count++;
if (count == newArray.Length)
break;
}
else
{
isFind = true;
}
}
if (isFind)
{
tempConfig.Items = newArray;
return;
}
else
return;
实际上,在数组本身不大的情况下(既不需要考虑起空间开销时),利用List<>和Array之间的转换就能写出简洁得多的代码,如代码段2:
bool isFind = false; //内存对象里是否包含待删除元素
foreach (FilesFile tempFile in contentInMemory.Items)
{
if (tempFile.Digest != file.Digest)
{
newArray[count] = tempFile;
count++;
if (count == newArray.Length)
break;
}
else
{
isFind = true;
}
}
if (isFind)
{
tempConfig.Items = newArray;
return;
}
else
return;
//代码段2
List<FilesFile> list = new List<FilesFile>(oldArray);
list.Remove(toDel);
contentInMemory.Items = list.ToArray();
List<FilesFile> list = new List<FilesFile>(oldArray);
list.Remove(toDel);
contentInMemory.Items = list.ToArray();
2.对于写文件,自己以前没有太注意过。潜意识里觉得,File.Open()方法实现应该是这样的:尝试去获取文件句柄,如果获取不到(正在被别的线程以互斥方式使用),当前线程睡眠一段时间之后再去尝试。写了代码段3一试,并非如此:
//代码段3
public class Even
{
public static void Main(string[] args)
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
File.Open(path, FileMode.Open, FileAccess.Write, FileShare.None);
Thread t = new Thread(new ThreadStart(TryRead));
t.Start();
Thread.Sleep(5000);
Console.Read();
}
public static void TryToRead()
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
FileInfo info = new FileInfo(path);
try
{
FileStream stream = File.OpenRead(path);
Console.WriteLine(stream.ReadByte());
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
Console.Read();
}
}
public class Even
{
public static void Main(string[] args)
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
File.Open(path, FileMode.Open, FileAccess.Write, FileShare.None);
Thread t = new Thread(new ThreadStart(TryRead));
t.Start();
Thread.Sleep(5000);
Console.Read();
}
public static void TryToRead()
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
FileInfo info = new FileInfo(path);
try
{
FileStream stream = File.OpenRead(path);
Console.WriteLine(stream.ReadByte());
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
}
Console.Read();
}
}
你会看到一个IOException被立刻抛出来。leafyang说得对,“谁知道那个文件会被占用到什么时候”,那么你要读写一个文件的时候,只能自己多try了。自己在项目中使用了代码段4:
//代码段4:获取一个非共享的可读可写的文件句柄
public static FileStream GetNotShareReadWriteStream(string path)
{
if ((path == null) || (!File.Exists(path)))
return null;
FileStream stream = null;
int tryCount = 0;
while (stream == null)
{
try
{
tryCount++;
if (tryCount > 10)
{
string info ="系统无法获取对文件{0}的写权限,请检查此文件的状态";
MessageBox.Show(string.Format(info, path));
return null;
}
stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
return stream;
}
catch
{
Thread.Sleep(50);
}
}
}
public static FileStream GetNotShareReadWriteStream(string path)
{
if ((path == null) || (!File.Exists(path)))
return null;
FileStream stream = null;
int tryCount = 0;
while (stream == null)
{
try
{
tryCount++;
if (tryCount > 10)
{
string info ="系统无法获取对文件{0}的写权限,请检查此文件的状态";
MessageBox.Show(string.Format(info, path));
return null;
}
stream = File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.None);
return stream;
}
catch
{
Thread.Sleep(50);
}
}
}
3.以前也写过类如
using (SqlConnection conn = new SqlConnection(...)){}
这样的代码,但其实没想过为什么这么写(汗一个)。事实上,using关键字被编译后的效果等同于一队try,catch,离开using作用域的时候会调用SqlConnection的Dispose方法。所以,这个关键字多用于像SqlConnection, FileStream之类的含有非托管资源的类型。如果你的一个自定义类型里打开了一些非托管资源,也可以让它实现IDisposeable接口,然后手工释放所有的资源。
注意,这个Dispose()方法的调用是无条件的,也就是说,这个要被Dispose的对象可能并不是在using中构造的,如代码段5:
//代码段5
public class Even
{
public static void Main(string[] args)
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
Test t = new Test();
TryDispose(t);
Console.Read();
}
public static void TryDispose(Test test)
{
using (test)//test并非在using内构造
{
test.DoSomething();
}
}
}
public class Test : IDisposable
{
public void DoSomething()
{
Console.WriteLine("I'm doing!");
}
public void Dispose()
{
Console.WriteLine("I am disposed!");
}
}
public class Even
{
public static void Main(string[] args)
{
string path = @"E:\Temp\CommonTest\coffee.jpg";
Test t = new Test();
TryDispose(t);
Console.Read();
}
public static void TryDispose(Test test)
{
using (test)//test并非在using内构造
{
test.DoSomething();
}
}
}
public class Test : IDisposable
{
public void DoSomething()
{
Console.WriteLine("I'm doing!");
}
public void Dispose()
{
Console.WriteLine("I am disposed!");
}
}
4.事务(TransactionScope)的局限
刚才异想天开,想用类似代码段6的代码来保证内存对象和硬盘上文件内容的同步:
//代码段6
using (TransactionScope scope = new TransactionScope())
{
this.AddFileToMemory(this.configContent, toAdd);
this.AddFileToConfig(toAdd);
scope.Complete();
}
这是起不到效果的,因为目前的事务支持仅限于数据库事务而已......using (TransactionScope scope = new TransactionScope())
{
this.AddFileToMemory(this.configContent, toAdd);
this.AddFileToConfig(toAdd);
scope.Complete();
}