C#学习笔记

  <system.webServer>

    <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[] { 1234} };

--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 TestDelegate(T i); 

内置匿名委托

Func 可传入指定类型参数最后一个为返回值类型

Action 可传入指定类型参数,但没有返回值 void

Predicate 可传入指定类型参数,自动返回 bool

Func<intintint> funcInt = add; 或写成  var fun = new Func<intintint>(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<stringintstring[]> extractMeth = delegate(string s, int i)

            {

                char[] delimiters = new char[] { ' ' };

                return i > 0 ? s.Split(delimiters, i) : s.Split(delimiters);

            };

 

 lambda 表达式

Func<stringintstring[]> 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 再转数组

int[] a = { 1, 2, 3, 4 };
List<int> al = new List<int>(a); 或者用Linq 的方式 List<int> s = a.ToList<int>();
int[] b = al.ToArray();    

 

 

 

 

 

 





posted @ 2017-12-15 09:45  夜.__.风  阅读(192)  评论(0)    收藏  举报