C#学习笔记
<staticContent>
<mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/x-font-woff" />
<mimeMap fileExtension=".lrc" mimeType="text/plain"/>
<mimeMap fileExtension=".ogg" mimeType="audio/mpeg"/>
<mimeMap fileExtension=".json" mimeType="application/x-javascript"/>
<mimeMap fileExtension=".apk" mimeType="application/vnd.android.package-archive"/>
</staticContent>
匿名
匿名对象
var obj = new {Guid.Empty, myTitle = "匿名类型", myOtherParam = newint[] { 1, 2, 3, 4} };
--Visual Studio 2013及以上才开始支持....
List<Person> family = new List<Person>
{
new Person {Name=Holly, Age=31},
new Person {Name=Jon, Age=31},
new Person {Name=Tom, Age=4},
new Person {Name=Robin, Age=1},
new Person {Name=William, Age=1}
};
初始化器
var myObj1 = new MyObj() { id = Guid.NewGuid(), Title = "allen" };
Predicate泛型委托
var d2 = new Predicate<int>(Less);
C#中的using
using (R r1 = new R ()) { r1.F(); }
前面的代码示例在编译时将扩展为以下代码
{//使用额外的大括号为对象创建限制范围
R r1 = new R();
try { r1.F(); }
finally { if (r1 != null) ((IDisposable)r1).Dispose(); }
}
R需要支持Dispose方法
如下面的示例所示,可以在 using 语句中声明一个类型的多个实例。
using (R r1 = new R (),R r2 = new R ())//注:VS2013才开始支持
{
// Use r1 and r2.
}
委托
委托是将方法当作参数来传递. 事件是把委托封装
public delegate string TestDelegate(int i);
int i = 99;
TestDelegate test = TestA;
test += TestB;
MessageBox.Show(test(i));
匿名方法
Var ss=delegate (string info) { lbInfo.Text = info;}
匿名委托
public delegate T TestDelegate(T i);
内置匿名委托
Func 可传入指定类型参数, 最后一个为返回值类型
Action 可传入指定类型参数,但没有返回值 void
Predicate 可传入指定类型参数,自动返回 bool型
Func<int, int, int> funcInt = add; 或写成 var fun = new Func<int, int, int>(add);
public int add(int a, int b)
{
return a + b;
}
调用 var i = fun(1, 2);
多委托.
public int add2(int a, int b)
{
return a + b;
}
funcInt +=add2;
var i = funcInt (1, 2);
接匿名方法
Func<string, int, string[]> extractMeth = delegate(string s, int i)
{
char[] delimiters = new char[] { ' ' };
return i > 0 ? s.Split(delimiters, i) : s.Split(delimiters);
};
接 lambda 表达式
Func<string, int, string[]> extract = (s, i) => i > 0 ? s.Split(separators, i) : s.Split(separators) ;
Lambda表达式
Lambda表达式:简化了匿名委托的使用,让你让代码更加简洁,优雅。据说它是微软自c#1.0后新增的最重要的功能之一
List<Person> persons = PersonsList();
persons = persons.Where(p => p.Age > 6).ToList()//(x,y)=>x*(y-1)
反射
反射是一种机制,通过这种机制我们可以知道一个未知类型的类型信息
获得了构造函数的信息,即可直接创建对象,即使这个对象的类型在编译时还不知道。
动态编译:运行时确定类型,绑定对象。发布后添加新功能,不必全部重新编译,
反射深克隆对象,不必重新赋值
缺点是对性能有影响
反射的用途:
(1)使用Assembly定义和加载程序集,加载在程序集清单中列出模块,以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。
反射绑定与调用的性能问题
(具体原理,大家参照微软CLR程序经理Joel Pobar在MSDN上的这篇文章):
https://msdn.microsoft.com/en-us/magazine/cc163759.aspx
1>首先要经过一个绑定过程,非常耗时(用字符串名称和metadata里面的字符串进行比对,字符串查找的算法大家都知道是很慢的操作)
2>然后要进行参数个数、类型等的校验;如果不匹配还要搜索可能的类型转换
3>进行CAS代码访问安全的验证,看允不允许调用。
4>以上几个工作,如果不用反射应该是由C#编译器负责在编译时检查的。但是现在如果用反射,全都放到了运行时检查。
5>这其中会产生一大堆的临时对象(比如MemberInfo Cache),给垃圾收集器造成巨大负担
6>纵然有一些对反射绑定和调用的cache优化策略,Joel Pobar在这篇文章中给的最大的建议还是:能不用反射,则不用反射,因为性能成本太高。
7>结论:反射调用的性能成本很高(参见msdn文章中中图2 Relative Performance of Invocation Mechanism)。
1. 反射的绑定和调用成本很高
—— C#反射绑定与调用过程中元数据字符串比对,参数校验,安全校验,大量临时对象,会让使用C#反射时的软件性能很差,尽量避免使用
2. 你不使用某些性能低的功能,不代表你依附的Application Framework不使用这些功能
—— 目前.NET平台中WPF/SL, WCF,WF, ASP.NET MVC等几大核心的框架都很重地使用了反射
3. 有些功能即便程序中不使用,为了支持这种机制,也要付出很高的代价
—— 哪怕所有的代码都是你写(不用Application Framework),而且不用一点反射的功能,C#编译器还是给你的软件中加了很多支持反射的metadata,占用很高昂的空间成本(大约是整个软件size的50%)
4. 只要有较大的空间成本,那么时间成本也一定很高
—— 反射背后的metadata占用的高昂的空间成本,由于内存加载、working set、cache missing 等各种问题,直接导致的时间成本很大,严重影响软件的运行性能。
http://www.cnblogs.com/firelong/archive/2010/06/24/1764597.html
各种反射调用性能比较
http://www.it165.net/pro/html/201206/2996.html

所以得出以下结论:
1. 不用反射,直接调用,效率最高。
2. 实例化反射,效率次之。
3. 快速反射,效率次之。
4. 传统反射,效率最差。
以上调用方式,后3种调用方式虽然效率有先后,但性能在一个数量级上,与传统反射相比,优越性较明显。
另外补充一点,实例化反射如果算上创建实例的性能损耗,试验结果如下图:

所以,如果需要频繁创建实例,建议不要采用实例化反射。
MethodInfo methodInfo = typeof(Person).GetMethod("Say");
Then, I get the MethodInvoker to invoke:
Hide Copy Code
FastInvokeHandler fastInvoker = GetMethodInvoker(methodInfo);
fastInvoker(new Person(), new object[]{"hello"});
作者重新实现了,反射调用方法,但是调用接口和.net原有方法一致。而且调用时抛出的异常为所调用类的实际异常,不像传统方式返回为包装异常。
http://www.codeproject.com/Articles/14593/A-General-Fast-Method-Invoker
内存泄露
1.非托管资源
a.COM 组件、ActiveX 接口和 Win32 API 函数
b.文件流,内存流,数据库链接
c.操作系统资源的对象
2.静态变量,方法
3.线程泄漏,创建了多线程而忘记清理
4.大型对象堆碎片, 大型对象堆中存放大型对象, 释放后不会进行碎片整理,使用过久后会产生很多内存碎片. 提高内存占用
5.未退订的事件
使用 int.TryParse 代替 int.Parse
不要将string=null,以免引起不必要的异常
String.Empty、string=”” 和null的区别
String.Empty是string类的一个静态常量;
String.Empty和string="" 区别不大,因为String.Empty的内部实现是:
public static readonly string Empty;
//这就是String.Empty 那是只读的String类的成员,也是string的变量的默认值是什么呢?
//String的构造函数
static String(){
Empty = "";//Empty就是他""
WhitespaceChars = new char[] {
'\t', '\n', '\v', '\f', '\r', ' ', '\x0085', '\x00a0', '-', ' ', ' ', ' ', ' ', ' ', ' ', ' ',
' ', ' ', ' ', ' ', '', '\u2028', '\u2029', ' ', ''
};
}
再看一段代码:
string s1 = "";
string s2 = string.Empty;
if (s1 == s2){
Console.WriteLine("一模一样!");
}
// 结果都是True
Console.WriteLine("".Equals(string.Empty));
Console.WriteLine(object.ReferenceEquals(string.Empty, ""));
既然String.Empty和string=””一样,同样需要占用内存空间,为什么推荐优先使用String.Empty ?
string.Empty只是让代码好读,防止代码产生歧义,多平台支持.
比如说:
string s = ""; string s = " "; 这个不细心看,很难看出是空字符串还是空格字符。
如果判断一个字符串是否是空串,使用
if(s==String.Empty)和if(s==””)的效率是一样的,但是最高效的写法是if(s.Length==0)
string.IsNullOrEmpty的内部实现方式:
public static bool IsNullOrEmpty(string value)
{
if (value != null)
{
return (value.Length == 0);
}
return true;
}
Equals对比值,==对比地址.
在定义变量的时候赋值,如果赋值的是静态的字符串,就会执行进入字符串池的操作,如果池中含有该字符串,则返回引用
String a =newString("ab") 采用new 创建的字符串对象不进入字符串池,地址自然不一样
两个集合对比
7,000,000条内用哈希会快点,内存占用较少
HashSet<T> hs = new HashSet<T>();
HashSet<T> hsc = new HashSet<T>();
foreach (T obj in a)
{
if (!hs.Contains(obj)) hs.Add(obj);
}
foreach (T obj in b)
{
if (hs.Contains(obj) && !hsc.Contains(obj)) hsc.Add(obj);
}
return hsc;
7,000,000以上,如效率比内存重要,则用下面的方法快些,内存会占得比较多
//循环B,验证元素是否存在
foreach (var item in B)
Btemp[item] = true;
//循环A,验证是否存在,将C对应位置标记为true
for (int i = 0; i < A.Length; i++)
if (Btemp[A[i]])
C[i] = true;
yyyy-MM-dd HH:mm:ss.fff
LinQ
List<city> list中查询拼接某个字段
lsi.ForEach(s => Section += s.Section + ",");
数组转List 再转数组

浙公网安备 33010602011771号