索引器
概念:索引器能够让我们的对象,以索引(下标)的形式,便捷地访问类中的集合(数组、泛型集合、键值对)
应用场景:
1、能够便捷地访问类中的集合
2、索引的数据类型、个数、顺序不固定的时候
索引器与数组的比较:
索引器的索引值(index)类型不受限制
索引器与属性的比较:
a、索引器可以被重载,属性不能
b、索引器不能声明为static,属性可以
internal class Program
{
static void Main(string[] args)
{
Person p = new Person();
Console.WriteLine(p[0]);
Console.WriteLine(p[1]);
p[2] = "张飞";
Console.WriteLine(p[2]);
Console.WriteLine(p["张三"]);
Console.WriteLine(p["李四"]);
p["王五"] = 100;
Console.WriteLine(p["王五"]); ;
Console.ReadKey();
Console.ReadKey();
}
}
class Person
{
//私有字段存储数组
private string[] names = { "张三", "李四", "王五", "赵六", "田七" };
//键值对
private Dictionary<string, int> dic = new Dictionary<string, int>();
//在构造函数里给键值对添加数据
public Person()
{
dic.Add("张三", 1);
dic.Add("李四", 2);
dic.Add("王五", 3);
dic.Add("赵六", 4);
}
//索引器
//string:表示通过索引器获取数据的类型
//this:表示索引器的名字,必须是this,不能修改
//index:索引的类型
public string this[int index]
{
get { return names[index]; }//通过索引取得数组中的值
set { names[index] = value; }//给数组中的某个元素赋值
}
//索引器是可以重载的
public int this[string key]
{
get { return dic[key]; }
set { dic[key] = value; }
}
}
索引器案例
internal class Program
{
//根据员工的姓名、编号,查找员工所在部门。
//根据员工的姓名、部门,查找员工的编号。
//根据员工的部门、编号,查找员工的姓名。
static void Main(string[] args)
{
EmployeeIndexer emps = new EmployeeIndexer();
string dep = emps["张三", 1];
if (!string.IsNullOrEmpty(dep))
{
Console.WriteLine(dep);
}
else
{
Console.WriteLine("查无此人");
}
int? id = emps["李四", "研发部"];
if (id != null)
{
Console.WriteLine(id);
}
else
{
Console.WriteLine("查无此人");
}
Console.ReadKey();
}
class Employee //员工类
{
public string Name { get; set; } //员工姓名
public int ID { get; set; } //员工编号
public string Department { get; set; } //员工部门
public Employee(string name, int iD, string department)
{
this.Name = name;
this.ID = iD;
this.Department = department;
}
}
class EmployeeIndexer //员工的索引类,负责对员工信息进行精确的查询
{
private List<Employee> listEmps = new List<Employee>();
public EmployeeIndexer()
{
listEmps.Add(new Employee("张三", 1, "行政部"));
listEmps.Add(new Employee("李四", 2, "财务部"));
listEmps.Add(new Employee("王五", 3, "研发部"));
listEmps.Add(new Employee("赵六", 4, "人事部"));
}
//根据员工的姓名、编号,查找员工所在部门。
public string this[string name,int id]
{
get
{
for (int i = 0; i < listEmps.Count; i++)
{
if (listEmps[i].Name == name && listEmps[i].ID==id)
{
return listEmps[i].Department;
}
}
return null;
}
}
//根据员工的姓名、部门,查找员工的编号。
public int? this[string name, string dep] // int? ? 可空的值类型
{
get
{
for (int i = 0; i < listEmps.Count; i++)
{
if (listEmps[i].Name == name && listEmps[i].Department == dep)
{
return listEmps[i].ID;
}
}
return null;
}
}
//根据员工的部门、编号,查找员工的姓名。
public string this[int id, string dep]
{
get
{
for (int i = 0; i < listEmps.Count; i++)
{
if (listEmps[i].ID == id && listEmps[i].Department == dep)
{
return listEmps[i].Name;
}
}
return null;
}
}
}
}
foreach的循环原理
1、要被循环的对象,需要实现IEnumerable接口
2、需要给被循环的对象,创建一个遍历的对象,并且要实现IEnumerator接口
3、 Current:返回当前遍历到的数据元素
MoveNext:判断时候可以继续向后循环,并改变index的值
Reset:重置索引
通过代码实现foreach
internal class Program
{
//foreach的循环原理
//只有实现了IEnumerable这个接口的对象才能被foreach
static void Main(string[] args)
{
Person p = new Person();
//获取遍历Person对象的人
IEnumerator enumerator = p.GetEnumerator();
//开始遍历
while (enumerator.MoveNext())
{
Console.WriteLine(enumerator.Current.ToString());
}
//IEnumerable :要被遍历的对象必须实现这个接口
//IEnumerator: 遍历对象的迭代器对象,要实现
Console.ReadKey();
//或者可以直接使用foreach
foreach (var item in p)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
class Person : IEnumerable
{
//IEnumerable : 接口,表示可以被foreach遍历的能力
//IEnumerator:真正做遍历集合这件事儿的人
//GetEnumerator:获取做遍历集合这件事儿的人
private string[] names = { "张三", "李四", "王五", "赵六", "田七" };
public IEnumerator GetEnumerator()
{
return new PersonEnumerator(names);
}
}
//枚举/迭代/遍历
class PersonEnumerator : IEnumerator
{
string[] myNames;
int index = -1;
//构造函数:获取要遍历的真实数据
public PersonEnumerator(string[] names)
{
this.myNames = names;
}
//Current表示返回当前遍历到的元素,object类型
public object Current
{
//索引没有越界的情况
get
{
if (index>=0&&index<this.myNames.Length)
{
return this.myNames[index];
}
return null;//数组越界了
}
}
//1、索引+1
//2、判断是否可以继续向后移动(+1),
//如果可以继续向后+1.则索引+1,并且返回true
//如果不可以向后+1,返回false
public bool MoveNext()
{
if (index+1<this.myNames.Length)
{
index++;
return true;
}
else
{
return false;
}
}
//重置索引,让索引回到原始位置
public void Reset()
{
index= -1;
}
}
泛型
概念:在某些情况,我们不想使用特定的数据类型,可以使用泛型
internal class Program
{
static void Main(string[] args)
{
Person<int> person = new Person<int>();
person.SayHi(199);
Person<string> person2 = new Person<string>();
person2.SayHi("张三");
Person<double> person3 = new Person<double>();
person3.SayHi_2<string>(3.14, "李四");
person3.SayHi_2(3.14);
double d = person3.SayHi_3(11.11);
Console.WriteLine(d);
int n = person3.SayHi_4<int>(3.14, 100);
Console.WriteLine(n);
int n2 = person3.SayHi_5<int>(3.14);
Console.WriteLine(n2);
Console.ReadKey();
}
}
//泛型类
class Person<T>
{
public void SayHi(T t)
{
Console.WriteLine(t);
}
//泛型方法
public void SayHi_2<K>(T t, K k)
{
Console.WriteLine(t);
Console.WriteLine(k);
}
//泛型方法也可以重载
public void SayHi_2(T t)
{
Console.WriteLine(t);
}
//返回值类型为T,参数为T
public T SayHi_3(T t)
{
return t;
}
//返回值类型为K,参数为T和K
public K SayHi_4<K>(T t, K k)
{
return k;
}
//返回值类型为K,参数为K
public K SayHi_5<K>(K k)
{
return k;
}
//泛型方法中的返回值如何处理?
//1、使用typeof关键字判断泛型的类型
//2、使用object作为中间量进行强制转换
//3、return defalut。default会返回数据类型的默认值
public K SayHi_5<K>(T t)
{
K k;
//如果k的类型是int
if (typeof(K) == typeof(int))
{
return (K)(object)100;
}
else if (typeof(K) == typeof(string))
{
return (K)(object)"Hello World";
}
else if (typeof(K) == typeof(double))
{
return (K)(object)3.14;
}
else
{
//返回K类型的默认值
return default;
}
}
//泛型接口
interface IFlayble<T>
{
void Fly(T t);
}
class Plane : IFlayble<string>
{
public void Fly(string t)
{
throw new NotImplementedException();
}
}
class Bird : IFlayble<int>
{
public void Fly(int t)
{
throw new NotImplementedException();
}
}
}
泛型约束
internal class Program
{
static void Main(string[] args)
{
Person<int> person = new Person<int>();
Student<Person<int>> student2 = new Student<Person<int>>();
Teacher<Animal> t1 = new Teacher<Animal>();
Teacher<Bird> t2 = new Teacher<Bird>();
Plane<IFly> plane = new Plane<IFly>();
Plane<MaQue> p2 = new Plane<MaQue>();
Computer<int, IComparable> cpu = new Computer<int, IComparable>();
Computer<FileStream, Stream> cpu2 = new Computer<FileStream, Stream>();
}
}
//泛型约束
//where 表示类型要符合的条件
class Person<T> where T : struct //值类型约束
{
}
class Student<T> where T : class, new() //引用类型约束
{
}
class Animal { }
class Bird : Animal { }
interface IFly
{
void Fly();
}
class MaQue : IFly
{
public void Fly()
{
}
}
class Teacher<T> where T : Animal { }
class Plane<T> where T : IFly { }
class Computer<T, U> where T : U { }
委托
概念:把方法作为参数,传递给另一个方法
委托,就是一个方法的指针
声明委托:public delegate(委托的关键字) 返回值类型 委托名称(参数列表)
使用委托:创建委托对象,指向某一个跟委托签名一致的方法(签名:参数和返回值)
internal class Program
{
public delegate void Del();//无参数无返回值的委托
public delegate void Del2(string name);//参数为string的委托
public delegate int Del3(string name, int age);//有两个参数,返回值为int类型的委托
static void Main(string[] args)
{
//虽然在代码层面没有创建委托对象,但是编译器在编译的时候,依然会帮助我们创建一个委托对象
//这个委托对象,在内存中指向M1方法
Del del = M1;//等同于 Del del = new Del(M1);
del(); //对M1方法的直接调用
del.Invoke();//对方法的间接调用
Del2 del2 = M2;
del2("张三");
del2.Invoke("李四");
Del3 del3 = M3;//委托与他指向的方法签名,必须完全一致,M4的话会报错
int res = del3("张三", 18);
Console.WriteLine(res);
Console.ReadKey();
}
static void M1()
{
Console.WriteLine("无参数无返回值的方法");
}
static void M2(string name)
{
Console.WriteLine("参数string,无返回值的方法");
Console.WriteLine(name);
}
static int M3(string name,int age)
{
Console.WriteLine("两个参数,返回值为int的方法");
Console.WriteLine(name);
Console.WriteLine(age);
return 100;
}
static int M4(int age,string name)
{
Console.WriteLine("和上面方法的参数类型不同");
return 200;
}
}
委托案例
{
public delegate string DelProStr(string str);
internal class Program
{
static void Main(string[] args)
{
//处理字符串数组
//1、给字符串数组的两边,添加双引号
//2、给字符串数组全部转换为大写
//3、给字符串数组全部转换为小写
string[] names = { "Jay", "James", "green", "blue" };
//SYH(names);
//StrToUpper(names);
//StrToLower(names);
ProcessStr(names, StrToSYH);
ProcessStr(names, StrToUpper);
foreach (var item in names)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
static void ProcessStr(string[] names, DelProStr del)
{
for (int i = 0; i < names.Length; i++)
{
names[i] = del(names[i]);
}
}
static string StrToSYH(string str)
{
return "\"" + str + "\"";
}
static string StrToUpper(string str)
{
return str.ToUpper();
}
static string StrToLower(string str)
{
return str.ToLower();
}
把数组中的每一个元素,加双引号
//static void SYH(string[] names)
//{
// for (int i = 0; i < names.Length; i++)
// {
// names[i] = "\"" + names[i] + "\"";
// }
//}
把数组中的每一个元素,转成大写
//static void StrToUpper(string[] names)
//{
// for (int i = 0; i < names.Length; i++)
// {
// names[i] = names[i].ToUpper();
// }
//}
把数组中的每一个元素,转成小写
//static void StrToLower(string[] names)
//{
// for (int i = 0; i < names.Length; i++)
// {
// names[i] = names[i].ToLower();
// }
//}
}
}
使用委托计算两个数的最大值
{
public delegate int DelCompare<T>(T o1, T o2); //比较o1和o2的值 让o1-o2 > 0
internal class Program
{
static void Main(string[] args)
{
//求数组的最大值 int string Person
int[] numbers = { 1, 2, 3, 43, 45 };
string[] names = { "ab", "James", "abcdefg" };
Person[] pers = { new Person() { Name = "张三", Age = 19 }, new Person() { Name = "李四", Age = 20 }, new Person() { Name = "王五", Age = 22 } };
int max = GetMax(numbers, GetIntMax);
string max2 = GetMax(names, GetStringMax);
Person max3 = GetMax(pers, GetPersonMax);
Console.WriteLine(max3.Name);
Console.WriteLine(max2);
Console.ReadKey();
}
static T GetMax<T>(T[] nums, DelCompare<T> del) //不同点1:返回值不一样 不同点2:参数不一样 不同点3:比较的方式不一样
{
T max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
//nums[i] > max
if (del(nums[i], max) > 0) //比较的方式,因为要比较的数据类型是不一样的,所以比较的方式也是不一样的。
{
max = nums[i];
}
}
return max;
}
static int GetIntMax(int o1, int o2)
{
//值类型---->引用类型:装箱
//int n1 = (int)o1;
//int n2 = (int)o2;
return o1 - o2;
}
static int GetStringMax(string o1, string o2)
{
//string s1 = (string)o1;
//string s2 = (string)o2;
return o1.Length - o2.Length;
}
static int GetPersonMax(Person o1, Person o2)
{
//Person p1 = (Person)o1;
//Person p2 = (Person)o2;
return o1.Age - o2.Age;
}
//求整数类型数组的最大值
//static int GetMax(int[] nums) //不同点1:返回值不一样 不同点2:参数不一样 不同点3:比较的方式不一样
//{
// int max = nums[0];
// for (int i = 0; i < nums.Length; i++)
// {
// if (nums[i] > max)
// {
// max = nums[i];
// }
// }
// return max;
//}
求字符串数组的最大值(字符串的长度)
//static string GetMax(string[] names)
//{
// string max = names[0];
// for (int i = 0; i < names.Length; i++)
// {
// if (names[i].Length > max.Length)
// {
// max = names[i];
// }
// }
// return max;
//}
求Person数组中,年龄最大的人
//static Person GetMax(Person[] pers)
//{
// Person max = pers[0];
// for (int i = 0; i < pers.Length; i++)
// {
// if (pers[i].Age > max.Age)
// {
// max = pers[i];
// }
// }
// return max;
//}
}
class Person
{
public int Age { get; set; }
public string Name { get; set; }
}
}
使用lambda表达式简化上述代码
public delegate int DelCompare<T>(T o1, T o2);//比较o1和o2的值
internal class Program
{
static void Main(string[] args)
{
//求数组的最大值 int string Person
int[] numbers = { 1, 2, 3, 4, 5 };
string[] names = { "ab", "abc", "avcdsf" };
Person[] pers = { new Person() { Name = "张三", Age = 18 }, new Person() { Name = "李四", Age = 20 }, new Person() { Name = "王五", Age = 25 } };
//调用泛型方法
int intMax = GetMax<int>(numbers, (a, b) => { return a - b; });//lambda表达式:方法的极致的简化写法
Console.WriteLine(intMax);
string stringMax = GetMax(names, (a, b) => { return a.Length-b.Length; });
//如果后面的参数,都是并且只有一个T,则<>可以省略,当你填入第一个参数的时候,所有的T就已经确定了
Console.WriteLine(stringMax);
Person personMax = GetMax(pers, (a, b) => { return a.Age-b.Age; });
Console.WriteLine(personMax.Name);
Console.ReadKey();
}
//写一个泛型方法,用于计算任意类型数组的最大值
static T GetMax<T>(T[]nums,DelCompare<T> del)
{
T max = nums[0];
for (int i = 0; i < nums.Length; i++)
{
if (del(nums[i],max)>0)
{
max = nums[i];
}
}
return max;
}
}
class Person
{
public int Age { get; set; }
public string Name { get; set;}
}