之前有总结发表过《近期开发项目中用到的编码小技巧汇总说明》,虽没有涉及什么高大上的东西,但都是一些很实用的平时大家可能用到的知识,今天继续分享一些小技巧,欢迎大家了解,不足之处,可以直接评论留言谢谢!
接上篇序号
6.解决当同一个类在不同的项目中(命名空间不同,但类的定义完全相同的情况)使用BinaryFormatter进行序列化后再反序列化时出现找不到程序集的问题或反序列化的结果为null
原代码:(DataSetSurrogate分别在API项目中,客户端项目中都存在,类定义一样但由于不在同一个项目,即使命名空间改成一样仍然是会报错的)
public static DataSet GZipBytesToDataSet(byte[] data)
{
byte[] buffer2 = data;
BinaryFormatter ser = new BinaryFormatter();
var ms = new MemoryStream(buffer2);
var obj = ser.Deserialize(ms);
DataSetSurrogate dss = obj as DataSetSurrogate;
return dss.ConvertToDataSet();
}
报错原因是:序列化后的byte数组中包含了程序集的信息,故如果想要在另一个程序集中成功的反序列化,则需要动态替换反序列化中的类型对应的程序集信息,改进后的代码:
先定义一个类型名称替换序列化绑定器:
public class TypeNameConvertBinder : SerializationBinder
{
public TypeNameConvertBinder():base()
{
}
public TypeNameConvertBinder(string oldNameSapce, string newNameSapce):this()
{
this.OldNameSapce = oldNameSapce;
this.NewNameSapce = newNameSapce;
}
public string OldNameSapce { get; set; }
public string NewNameSapce { get; set; }
public override Type BindToType(string assemblyName, string typeName)
{
typeName = typeName.Replace(OldNameSapce, NewNameSapce);
assemblyName = assemblyName.Replace(OldNameSapce, NewNameSapce);
return Type.GetType(string.Format("{0}, {1}", typeName, assemblyName));
}
}
然后序列化的时候直接给 BinaryFormatter设置Binder即可,代码如下:
public static DataSet GZipBytesToDataSet(byte[] data)
{
byte[] buffer2 = data;
BinaryFormatter ser = new BinaryFormatter();
ser.Binder = new TypeNameConvertBinder() { OldNameSapce = "WMS.Common", NewNameSapce = "Zuowj" };
var ms = new MemoryStream(buffer2);
var obj = ser.Deserialize(ms);
DataSetSurrogate dss = obj as DataSetSurrogate;
return dss.ConvertToDataSet();
}
以上这样就解决了序列化时因为程序集不相同而导致的反序列化失败的问题。
7.控制台程序中实现输入密码遮罩功能,这个功能我是摘抄自网上的,还可以有优化空间
实现代码如下:
static string ReadLineForPassword()
{
string input = null;
while (true)
{
//存储用户输入的按键,并且在输入的位置不显示字符
ConsoleKeyInfo ck = Console.ReadKey(true);
//判断用户是否按下的Enter键
if (ck.Key != ConsoleKey.Enter)
{
if (ck.Key != ConsoleKey.Backspace)
{
//将用户输入的字符存入字符串中
input += ck.KeyChar.ToString();
//将用户输入的字符替换为*
Console.Write("*");
}
else
{
if (!string.IsNullOrEmpty(input)
&& input.Length >= 1)
{
input = input.Remove(input.Length - 1, 1);
}
//删除错误的字符
Console.Write("\b \b");
}
}
else
{
Console.WriteLine();
break;
}
}
return input;
}
//使用:
string token = ReadLineForPassword();
这样当用户在控制台上输入密码时则会以*号隐藏掉了。
8.直接使用String拼接XML的时候,有时可能因为字符串中包含了XML的保留字符,那么拼成后就会报错,故需要转义这些保留字,如果自己写可能考虑得不全,这时可以使用:SecurityElement.Escape(String) 方法进行转义即可。
原来的代码:
var st =new System.Diagnostics.StackTrace();
string msg = "<key>无效,使用'key'也无效 ";
string xml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><root><Msg>" + msg + "</Msg><StackTrace>" + st.ToString() + "</StackTrace></root>";
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xml);
StringBuilder strBuilder=new StringBuilder();
using (var xmlWriter = XmlWriter.Create(strBuilder))
{
xmlDoc.WriteTo(xmlWriter);
}
Console.WriteLine("new xml:" + strBuilder.ToString());
Console.ReadKey();
执行到xmlDoc.LoadXml(xml);报错,因为msg中包含了XML的保留字符,改进一下 msg = System.Security.SecurityElement.Escape("<key>无效,使用'key'也无效 ");然后再用同样的代码即可正常显示完整的XML,结果如下:
可以看到XML的保留字符都被转义了。
好了今天就先分享到这里,后续会继续补充更新,敬请期待!