这周是第一次在力扣上上做题
跟着代码随想录的目录刷了些dp题目,能dp做的题目,本质上都可以通过回溯暴搜做出来,只不过大多会超时,通过这些题目以及大佬提供的思路,dp题目的基本思想如下->无论是几维dp,一定要先明确dp[i]所表示的含义,比如在01背包中,dp[i]表示在背包容量为i的情况下,所能装进的物品的最大价值为dp[i]。
2.在确定好了dp数组是什么意思后,通过dp数组前后状态之间的联系,确定状态转移方程,即下一个状态是由哪几个状态所决定的,推出递推公式
3.明确dp数组的初始化,而并非一上来就无脑memset(dp,0,sizeof dp);
4.正确考虑遍历顺序,如何对dp数组进行遍历?正序遍历还是倒序遍历?需要结合实际情况进行统筹的分析
5.通过举例推到状态数组是否正确,和预期结果是否有偏差,有偏差了就可以先打印dp数组查看哪里出现了问题
unity学习日志:
这周是把唐老狮unity入门全听完了,回去听了C#进阶的知识
首先是泛型类和泛型接口->
泛型类:
class Test
{
public T a;
泛型函数:public void TestFun(K value)
}
在主函数里: Test test1 = new test();
test1.a = 10;
test1.TestFun("1234567"); //泛型函数的使用
在泛型类中还可以定义泛型接口,泛型类可以用where约束其范围
其次是委托和事件,委托和事件的差异貌似不是特别大,区别主要在于事件不能在类的外部去赋值的,但可以在类外部+=或-=函数,委托和事件可以理解成都是装载函数的容器,委托格式:
delegate void TestFun();
调用时的几种写法:TestFun f = new TestFun(Fun);
public void Fun(){
}
相当于是把Fun这个函数暂时存储在了委托变量TestFun中
什么时候可以通过委托调用这个函数?
f.Invoke();调用
第二种存储函数的方式:TestFun f2 = Fun;
f2(); 调用Fun函数
同时值得注意的是->你声明委托时参数列表是什么样的,委托变量就只能存储参数列表对应相同的函数
而且委托一般是用在类的成员变量和函数参数中
系统定义好的委托需要引用命名空间System
Action action = Fun; //无参无返回值的委托
Action<int,string> action = Fun; //指定参数为int、string的委托
Func<string> fun = Fun; //指定返回值为string的委托
Func的泛型中写n个,则以第一个为准作为返回值,剩下的是作为参数使用
Func<string,int> fun = Fun; 返回值为string,参数有一个,为int类型
关于事件->
如何声明事件→public event Action myEvent;
关于事件的启用和委托是一样的
如果想调用事件,可以在类内部封装一个方法,在该方法中去调用事件
关于匿名函数->
无参无返回值的写法->
有参数->
返回什么会自动识别→所以只需要用对应的委托接受就行
匿名函数一般情况下会作为函数参数传递 或者作为函数返回值
关于lambad表达式以及闭包->
究其本质→闭包捕获的是变量的引用而不是变量的值
举例如下:
当在外部启用事件的的时候,会打印10次10,而不是打印0~9,为什么呢?因为当在for循环结束之前,事件一直没有被调用,且i的声明周期变长了,所以i的栈空间一直未被释放,也就是说同一块空间的地址被存放到了容器当中,只是改变了该空间中的值,以至于事件调用的时候获取的值只会是i最终的值10
也就是说该变量提供的值并非变量创建时的值而是在父函数范围内的最终值
究其本质→闭包捕获的是变量的引用而不是变量的值
那我如果就是想要让0~9被存进去呢?
可以在action+=()=>上面设置一个临时变量,每次循环进来时都临时创建一个变量用来存储i的值
即for(int i=0;i<10;i++){
int index = i;
action+=()=>{
Console.WriteLine(index);
}
}
反射部分
什么是程序集?
程序集就是我们写的一个代码集合,我们现在写的所有代码
最终都会被编译器翻译为一个程序集供别人使用
比如一个代码库文件(dll)或者一个可执行文件(exe)
什么是元数据?
程序中的类,类中的函数、变量等等信息就是 程序的 元数据
有关程序以及类型的数据被称为 元数据,它们保存在程序集中
有关反射的定义
程序正在运行时,可以查看其它程序集或者自身的元数据。
一个运行的程序查看本身或者其它程序的元数据的行为就叫做反射
反射的作用
因为反射可以在程序编译后获得信息,所以它提高了程序的拓展性和灵活性
1.程序运行时得到所有元数据,包括元数据的特性
2.程序运行时,实例化对象,操作对象
3.程序运行时创建新对象,用这些对象执行任务
反射语法相关→
Type(类的信息类)
它是反射功能的基础!
它是访问元数据的主要方式。
使用 Type 的成员获取有关类型声明的信息
有关类型的成员(如构造函数、方法、字段、属性和类的事件)
获取Type→
//1.万物之父object中的 GetType()可以获取对象的Type
int a = 42;
Type type = a.GetType();
Console.WriteLine(type);
//2.通过typeof关键字 传入类名 也可以得到对象的Type
Type type2 = typeof(int);
Console.WriteLine(type2);
//3.通过类的名字 也可以获取类型 // 注意 类名必须包含命名空间 不然找不到
Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);
这三种方式获取的Type本质上是一样的,即使三个临时变量在栈空间中存在于三个不同的地址,但实际上这三个栈空间的地址都指向同一个堆空间的地址
也就是说一种类型的Type只有一份,int 类型的Type有且只有一份
即一种类型的元数据只有一份
得到类的程序集信息(不常用)
//可以通过Type可以得到类型所在程序集信息
Console.WriteLine(type.Assembly);
Console.WriteLine(type2.Assembly);
Console.WriteLine(type3.Assembly);
获取类中的所有公共成员
//首先得到Type Type t = typeof(Test);
值得注意的是,在同一程序集中,获取自己的程序集一般用的是typeof,获取外部的程序集一般都是通过它的名字去获得的Type.GetType("名字");
//然后得到所有公共成员 //需要引用命名空间 using System.Reflection;
MemberInfo[] infos = t.GetMembers();
//公共成员的类数组 for (int i = 0; i < infos.Length; i++) { Console.WriteLine(infos[i]); }
获取类的公共构造函数并调用→
//1.获取所有构造函数 ConstructorInfo[] ctors = t.GetConstructors();
for (int i = 0; i < ctors.Length; i++) { Console.WriteLine(ctors[i]); }
//2.获取其中一个构造函数 并执行
//得构造函数传入 Type数组 数组中内容按顺序是参数类型
//执行构造函数传入 object数组 表示按顺序传入的参数
// 2-1得到无参构造 ConstructorInfo info = t.GetConstructor(new Type[0]);
//执行无参构造 无参构造 没有参数 传null
Test obj = info.Invoke(null) as Test;
Console.WriteLine(obj.j);
// 2-2得到有参构造
ConstructorInfo info2 = t.GetConstructor(new Type[] { typeof(int) });
obj = info2.Invoke(new object[] { 2 }) as Test;
Console.WriteLine(obj.str);
ConstructorInfo info3 = t.GetConstructor(new Type[] { typeof(int), typeof(string) });
obj = info3.Invoke(new object[] { 4, "444444" }) as Test;
Console.WriteLine(obj.str);
获取类的公共成员变量
//1.得到所有成员变量 FieldInfo[] fieldInfos = t.GetFields();
for (int i = 0; i < fieldInfos.Length; i++) { Console.WriteLine(fieldInfos[i]); }
//2.得到指定名称的公共成员变量 FieldInfo infoJ = t.GetField("j");
Console.WriteLine(infoJ);
//3.通过反射获取和设置对象的值 Test test = new Test();
test.j = 99; test.str = "2222";
// 3-1通过反射 获取对象的某个变量的值
Console.WriteLine(infoJ.GetValue(test));
// 3-2通过反射 设置指定对象的某个变量的值
infoJ.SetValue(test, 100); Console.WriteLine(infoJ.GetValue(test));
获取类的公共成员方法
//通过Type类中的 GetMethod方法 得到类中的方法
//MethodInfo 是方法的反射信息
Type strType = typeof(string);
MethodInfo[] methods = strType.GetMethods();
for (int i = 0; i < methods.Length; i++) { Console.WriteLine(methods[i]); }
//1.如果存在方法重载 用Type数组表示参数类型
MethodInfo subStr = strType.GetMethod("Substring", new Type[] { typeof(int), typeof(int) });
//2.调用该方法 //注意:如果是静态方法 Invoke中的第一个参数传null即可
string str = "Hello,World!";
//第一个参数 相当于 是哪个对象要执行这个成员方法
object result = subStr.Invoke(str, new object[] { 7, 5 });
Console.WriteLine(result);
获取一些其它成员的方法→
Type;
得枚举
GetEnumName
GetEnumNames
得事件
GetEvent
GetEvents
得接口
GetInterface
GetInterfaces
得属性
GetProperty
GetPropertys
等等
Activator类
//用于快速实例化对象的类
//用于将Type对象快捷实例化为对象
//先得到Type //然后 快速实例化一个对象
Type testType = typeof(Test);
//1.无参构造
Test testObj = Activator.CreateInstance(testType) as Test;
Console.WriteLine(testObj.str);
//2.有参数构造
testObj = Activator.CreateInstance(testType, 99) as Test;
Console.WriteLine(testObj.j);
testObj = Activator.CreateInstance(testType, 55, "111222") as Test;
Console.WriteLine(testObj.j);
Assembly类
//程序集类 //主要用来加载其它程序集,加载后 //才能用Type来使用其它程序集中的信息 //如果想要使用不是自己程序集中的内容 需要先加载程序集 //比如 dll文件(库文件) //简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类
//三种加载程序集的函数 //一般用来加载在同一文件下的其它程序集
//Assembly asembly2 = Assembly.Load("程序集名称");
//一般用来加载不在同一文件下的其它程序集
//Assembly asembly = Assembly.LoadFrom("包含程序集清单的文件的名称或路径");
//Assembly asembly3 = Assembly.LoadFile("要加载的文件的完全限定路径");
//1.先加载一个指定程序集 Assembly asembly = Assembly.LoadFrom(@"C:\Users\MECHREVO\Desktop\CSharp进阶教学\Lesson18练习题\bin\Debug\netcoreapp3.1\Lesson18练习题");
Type[] types = asembly.GetTypes();
for (int i = 0; i < types.Length; i++) { Console.WriteLine(types[i]); }
//2.再加载程序集中的一个类对象 之后才能使用反射
Type icon = asembly.GetType("Lesson18练习题.Icon");
MemberInfo[] members = icon.GetMembers();
for (int i = 0; i < members.Length; i++) { Console.WriteLine(members[i]); }
//通过反射 实例化一个 icon对象 //首先得到枚举Type 来得到可以传入的参数
Type moveDir = asembly.GetType("Lesson18练习题.E_MoveDir");
FieldInfo right = moveDir.GetField("Right");
//直接实例化对象
object iconObj = Activator.CreateInstance(icon, 10, 5, right.GetValue(null));
//得到对象中的方法 通过反射
MethodInfo move = icon.GetMethod("Move");
MethodInfo draw = icon.GetMethod("Draw");
MethodInfo clear = icon.GetMethod("Clear");
Console.Clear();
while(true)
{
Thread.Sleep(1000);
clear.Invoke(iconObj, null);
move.Invoke(iconObj, null);
draw.Invoke(iconObj, null);
}
3.类库工程创建
创建的类库工程没用控制台信息,会生成dll文件,因此我们可以在类库工程中写代码,然后通过反射去调用
如何创建→在解决方案中选择添加新项目→找到类库(.NET Framework)C#类库(dll)的项目→创建
在其中写好代码后,可以在解决方案资源管理器中右击该项目,选择生成,然后就会生成dll文件,可以右击选择访问该文件目录(在bin→debug中)