C# - 常用类

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# - 常用类相关的知识,希望对你有一定的参考价值。

常用类

Object类

所有类的基类,为所有类提供了通用的低级别服务。别名:object

static Equals(object obj1, object obj2)
//比较相等性,返回bool值
//引用类型比较堆地址,值类型比较值
//String、StringBuilder对象重写了Equals方法,字符的Equals方法比较值而非引用

static ReferenceEquals(obj1, obj2)
//比较相等性,返回bool值
//引用类型比较堆地址
//值类型装箱后再比较,必然返回false

Equals(object conpareObj)
//比较相等性,返回bool值
//引用类型比较堆地址,值类型比较值
//比较相等性,返回bool值
//引用类型比较堆地址,值类型比较值
//String对象重写了Equals方法,字符的Equals方法比较值而非引用

GetType()
//获取对象的元数据
//示例:
string s = "";
s.GetType()==typeof(string)

ToString()
//返回对象的字符表示,但很多类型都重写了此方法,具体返回值视派生类对此方法的实现而定。

protected MemberwiseClone()
//返回对象的浅拷贝 这是一个受保护的方法,只能在派生类内部引用以便拷贝对象的浅副本

Object的可重写的虚成员方法

ToString()

类型的ToString()方法默认返回类型的完全限定名的字符表示,如果想让类的ToString()方法返回更有意义的文本,可考虑重写此方法。

Equals()

默认值类型比较值的等同性,引用类型比较地址的等同性。如果有特殊需求,可考虑重写此方法,如果确实要重写它,那么同时必须要重写GetHashCode()方法。

GetHashCode()

获取对象的哈希值。 

为什么重写Equals()方法时必须重写GetHashCode()方法?

哈希值可以用来标识一个对象的唯一性,但不是说哈希值不会重复,只是说可以利用哈希值标识对象,也即哈希值本身是容易重复的。两个引用相同或值相同的对象,它们的哈希值绝对相等,但两个不同的对象的哈希值也有可能是相等的。对于单个对象,重写哈希值没有任何实际的意义,比如当对象调用Equals()方法时并不会进入GetHashCode()方法而是直接用Equals()方法进行相等性测试。

但泛型字典会调用集合中的Key的GetHashCode()方法,所以要考虑到某个对象可能会存储在泛型字典集合中(哈希表),这样,哈希值就能发挥它的威力,哈希值可以提升查找的效率,比如泛型字典集合就是使用哈希值来表示字典的key,查找项时其速度可以得到很大的提升。Dictionary<TKey,TValue>是用key来作为记录的键,key必须具有唯一性,否则运行时将抛出异常。字典会调用key的GetHashCode(),将返回的哈希值当做一条记录的唯一标识以便能根据这个标识找到对应的记录。

Dictionary<string, object> dictionary = new Dictionary<string, object>
{
    { "1","sam" }, //Key是1的字符表示,该字符是string类型,当向字典插入key时,会自动调用string对象的GetHashCode方法获取字符1的哈希值
    { "2","sam" } 
};

为什么不直接查询key,而是非要用key的哈希值作为查找的手段?因为哈希值的查询效率较高。在默认情况下,当向字典添加一个键值对时,它会调用该键值对的key的GetHashCode(),然后查找哈希表中是否有另一个key也具有相同的哈希值,如果没有,就将该键值对添加到哈希表中,如果已经有一个键值对的key和刚才试图添加的键值对的key具有相同的哈希值,那么根据不同对象也可能具有相同的哈希值,Dictionary<TKey,TValue>就会进一步判断key的相等性。

public class Animal 
{
    public string Name { get; set; }
    public override bool Equals(object animal)
    {
        if(((Animal)animal).Name==this.Name)
        {
            return true;
        }
        return false;
    }       
}
class Program
{
    static void Main(string[] args)
    {
        Animal animal = new Animal { Name = "sam" };
        Animal animal2 = new Animal { Name = "leo" };
        Dictionary<Animal, int> list = new Dictionary<Animal, int>
        {
            { animal,1},
            { animal,2 } //编译器错误列表会显示错误,提示Animal已经重写了Equals,则表示你不想按照默认的相等性比较器来比较两个对象的等同性,所以你需要重写object的GetHashCode
        };
    }
}

Dictionary<TKey,TValue>会自动调用key的Equals方法对集合中的key进行比较判断,Equals()方法默认比较的是:如果两个操作数是值类型,那么测试值是否相等,如果是引用类型则测试它们指向的堆上的地址是否相等,从而返回一个布尔值让泛型字典确定新添加的key是否在集合中已经有了一个相同的key。也即字典先调用对象的GetHashCode,如果该对象的HashCode已经存在,再退而求其次调用Key的Equals方法去比较对象的等同性。

所以如果你需要重写Equals()方法,那么必须重写GetHashCode()方法,这是为了满足Dictionary<TKey,TValue>字典集合对HashCode的要求。毕竟GetHashCode的查找效率很高。如果不重写GetHashCode(),编译器会提示警告。但假如写不出高质量的GetHashCode(),那就随便return一个低劣的hashcode好了,这样,在泛型字典集合中,当试图添加一个在字典中已经存在的哈希值所对应的key时就会发生冲突,然后泛型字典集合会进入key的Equals()方法进行判断以便确认两个key究竟是否相等,如果相等,则编译器会提示你禁止添加相同的Key。 

通常,我们向泛型字典添加的key的类型都是int或string类型,一般情况都不会将自定义类型(比如自定义的Animal类)作为key来使用。所以,假设现在我们想重写Animal的Equals方法,那么在我们根本不需要将Animal作为泛型字典的key的同时却又必须重写GetHashCode方法,这也太坑爹了,解决方法是让Animal类实现IEquatable<T>接口。参看:IEquatable<T>接口

 

1.==和!=操作符 

2.Equals()方法 

Object提供了virtual的Equals()实例方法,你可以重写这个比较的规则。

3.Object.Equals(object x,object y)静态方法

假设x调用实例Equals方法,而x如果是一个null,这会引发异常,为了解决这个问题,才引入了静态的Equals方法,此方法是对Equals实例方法的封装,在不明确x是否为null的情况下,可以使用object.Equals(x,y),该静态方法将测试x和y是否同时为null,如果是则返回true,否则如果x为null,则返回false,否则将调用x.Equals(y)进行相等性判断。

4.Object.ReferenceEquals(object x,object y)静态方法

此方法判断对堆上地址的引用的等同性,可能很多时候你用不上这个方法,但,假设你重写了Equals()方法,比如将Equals()方法重写为只要两个对象的某个属性值是相等的就返回true。这样一来,假设下一次你还想测试引用地址的等同性,Equals就做不到了,而且直接调用静态的object.Equals()方法,该方法也会调用被重写的实例的Equals(),所以才有了一个ReferenceEquals这样的后备军。

 

String类

封装一系列不可改变的字符,实例一旦创建就会固着在内存中直到被回收。别名:string

static Compare(strA, strB)
//比较两个字符的大小,前者<后者,结果<0,前者>后,结果>0,前者=后者,结果=0,null<任何字符。有10个重载,可区分大小写、可提供子串索引比较子串大小、可提供自定义比较规则等

static Concat(IEnumerable<string> strValue)
//将实现了IEnumerable<T>接口的集合元素当做字符串连接在一起,返回这个字符串
//示例:
string[] y = { "bb", "cc" };
string r = string.Concat(y); // print "bbcc"

static Join(string Operator, IEnumerable<string> strValue)
//将实现了IEnumerable<T>接口的集合元素当做字符串,将每个元素通过Operator字符连接在一起并返回这个字符串
 
new string( char,count )
//创建指定个数的char字符
string s = new string( \'a\', 100 ); //100个a

new string( charArray )
//将char[]数组转换为字符串
char[] charArray = { \'a\', \'b\', \'c\' };
string str = new string( charArray );
Console.WriteLine( str ); //print abc
//字符由一系列的char组成,所以,string可以像数组元素般被检索 如:
char charStr = "sam"[0];

ToLower( )
//转换为小写

ToUpper( )
//转换为大写

IndexOf( str )
//查询参数指定的str在字符中的索引,查不到返回-1,可提供查找的起始索引和查找个数,类似的有LastIndexOf(),

IndexOfAny( string[] sArray )
//查询参数指定的数组中的每个字符最早在字符串中出现的索引,只要有一个字符被查到就立即返回,查不到返回-1,
//可提供查找的起始索引和查找个数,类似的有LastIndexOfAny(),返回指定数组中的任意一个字符在字符串中最后一次出现的索引

StartsWith( str )
//是否以str开头

EndsWith( str )
//是否以str结尾

Trim( )
//移除字符的首尾连续的(未被其它字符阻断)的空格,类似的有TrimStart()、TrimEnd()
//如果参数接收一个char[]数组,则删除字符中的前导连续和尾部连续的(未被其它字符阻断的)字符中出现在char数组中的任意一个char字符
//示例:
string str = "abcdefgag";
Console.WriteLine( str.Trim( "ag".ToCharArray( ) ) ); //bcdef
//例子中的ag在cha[]中,所以str中的前面部分出现在cha[]数组中的未被其它字符阻断的字符会被删除,尾部同样是这样的逻辑

Remove( startIndex )
//移除指定索引处的字符

Replace( oldStr, newStr )
//用newStr替换olStr,全文替换

Split( string[] | char[] )
//以参数指定的字符将字符串分割成数组
string s = "s:a:m";
string[] aa = s.Split( new char[] { \':\' }, 2 ); //用参数指定的字符将"s:a:m"分隔成存储两个字符的数组:[\'s\',\'a:m\']
string s2 = "xxxaadd";
s2.Split( new string[] { "aa" }, StringSplitOptions.RemoveEmptyEntries );

Substring( startIndex, length )
//提取指定个数的子字符,如果length不存在则提取到结束索引,包括结束索引。

Array类

static ConvertAll(Array array, Converter<TInput, TOutput>)
//将参数数组转换为另一种数组类型
//示例:字符串数组转int数组
string[] xUserIDs = { "1", "2" };
int[] userIDs = Array.ConvertAll(xUserIDs, o => int.Parse(o)); //迭代数组每个元素,转换为int类型

static IndexOf(Array array, value)
//与字符串的查找是一样的 类似的还有LastIndexOf()

static Reverse(Array array)
//将一维数组元素倒转

static Sort(Array array, IComparable<T> comparable)
//从小到大排序,隐式地迭代数组元素,每迭代一次则自动调用元素实现的IComparable<T>接口的CompareTo方法,该方法会比较每个元素的大小,Sort方法在默认情况下是对元素按从小到大进行排序
//示例:
int[] ints = { 100, 5, 8 };
Array.Sort(ints); //隐式调用了int实现的IComparable<T>接口的CompareTo方法比较元素的大小,按从小到大排序
Console.WriteLine(ints[0]); //print 5
//示例:你可以自定义元素的IComparable<T>接口实现,以便Sort方法可以按照你定义的比较大小的规则进行排序
//以下假设Student实现了IComparable<T>接口的CompareTo方法,用来比较学生的成绩
Student[] stus = { new Student { Score = 100 }, new Student { Score = 90 } };
Array.Sort(stus);
Console.WriteLine(stus[0].Score);  //print 90

static Sort(Array array, IComparer<T> comparer)
//从小到大排序,隐式地迭代数组元素,每迭代一次则自动调用 IComparer<T>实例的Compare方法用以对元素进行排序

static Sort(Array array , Comparison<T> comparison)
//comparison:指定一个匹配Comparison<T>(T t1,T t2)签名的泛型委托用以比较排序,比如一个Lambda表达式
//从小到大排序,Sort方法隐式地迭代数组元素,每迭代一次则自动调用comparison
Student[] stus = { new Student { Score = 100 }, new Student { Score = 90 } };
Comparison<Student> comparison = (item1, item2) => { return item1.Score > item2.Score ? 1 : item1.Score < item2.Score ? -1 : 0 };
Array.Sort(stus, comparison);
Console.WriteLine(stus[0]); //print 90

 

C# - 学习总目录

以上是关于C# - 常用类的主要内容,如果未能解决你的问题,请参考以下文章

C#常用工具类——Excel操作类(ZT)

C#常用操作类库三(XML操作类)

C# - 常用类

C#常用的正则工具类写法

C#常用开源类库

C#常用的HttpGet HttpPost HttpDownload方法类