二叉树建立

 

//配置一个二叉树
int i = 1;
TreeNode tree = null;
List<int> ints =new List<int>{ 1, 2, 3, 4, 5, 6, 7, 8 };

tree = SetATree(ints,0,ints.Count());
Console.WriteLine("PreOrder:");
PreOrder(tree);
Console.WriteLine("MidOrder:");
MidOrder(tree);
Console.WriteLine("PostOrder:");
PostOrder(tree);

TreeNode SetATree(List<int> j,int index,int len)
{
    if (j==null || j.Count == 0)
        return null;
    TreeNode treeNode = null;
    if (index < len)
    {
        treeNode = new TreeNode(j[index]);
        treeNode.LeftNode = SetATree(j, 2*index + 1, len);
        treeNode.RightNode = SetATree(j, 2*index + 2, len);
    }
    return treeNode;
}

//前序遍历
void PreOrder(TreeNode tree)
{
    if (tree == null)
        return;
    Console.WriteLine(tree.Data);
    PreOrder(tree.LeftNode);
    PreOrder(tree.RightNode);
}

//中序遍历
void MidOrder(TreeNode tree)
{
    if (tree == null)
        return;
    MidOrder(tree.LeftNode);
    Console.WriteLine(tree.Data);
    MidOrder(tree.RightNode);
}

//后序遍历
void PostOrder(TreeNode tree)
{
    if (tree == null)
        return;
    PostOrder(tree.LeftNode);
    PostOrder(tree.RightNode);
    Console.WriteLine(tree.Data);
}

  

平衡二叉树

平衡二叉树可定义为或者是一棵空树,或者是具有下列性质的二叉树:其左子树和右子树均为平衡二叉树,且左子树和右子树的高度差的绝对值不超过1。注意:平衡二叉树一定是二叉排序树。含有n个结点的平衡二叉树的最大深度为O(log2(n)),即平衡二叉树的平均查找长度为O(log2(n))。

  

(1)RR平衡旋转(左单旋转)

前提条件:右子树的高度减去左子树的高度大于1,即:rightHeight() - leftHeight() > 1。

(1)创建一个新的结点newNode,使其值等于当前根结点的值;
(2)将新结点的左子树设置为当前结点的左子树:newNode.left=left;
(3)将新结点的右子树设置为当前结点的右子树的左子树:newNode.right =right.left;
(4)将当前结点的值换为右子结点的值:value=right.value;
(5)将当前结点的右子树设置成右子树的右子树:right=right.right;
(6)将当前结点的左子树设置成新结点:left=newNode。
————————————————
将父节点为左侧旋转至左侧子节点
将子节点的左侧孙节点变为原来的左侧父节点
newNode.data=old.data
newNode.Left=old.left
newNode.Right=old.right.left
old=old.right.data
old.left=newNode
old.right=old.right.right

  

(2)LL平衡旋转(右单旋转)

前提条件:左子树的高度减去右子树的高度大于1,即:leftHeight() - rightHeight() > 1。

(1)创建一个新的结点newNode,使其值等于当前根结点的值;
(2)将新结点的右子树设置为当前结点的右子树:newNode.right=right;
(3)将新结点的左子树设置为当前结点的左子树的右子树:newNode.left =left.right;
(4)将当前结点的值换为左子结点的值:value=left.value;
(5)将当前结点的左子树设置成左子树的左子树:left=left.left;
(6)将当前结点的右子树设置成新结点:right=newNode。
————————————————
将原来的左侧节点变成根节点,原来的左侧右节点替换为跟节点,新右节点的左子节点变为原来的右节点
newNode.data=old.data
newNode.left=old.left.right
newNode.right=old.right
old.data=old.left.data
old.left=old.left.left
old.right=newNode

  

(3)LR平衡旋转(先左后右双旋转)

前提条件:符合RR平衡旋转(左单旋转)前提下,当前结点的左子树的右子树高度大于它的左子树的左子树的高度,即:left.rightHeight()>left.leftHeight()。
(1)先对当前结点的左结点进行左单旋转;
(2)再对当前结点进行右单旋转即可。

  

(4)RL平衡旋转(先右后左双旋转)

前提条件:符合LL平衡旋转(右单旋转)前提下,当前结点的右子树的左子树的高度大于它的右子树的右子树的高度,即: right.leftHeight()>right.rightHeight()。

(1)先对当前结点的右结点进行右单旋转;
(2)再对当前结点进行左单旋转即可。

  


聚集索引和非聚集索引

区别:
1.聚集索引一个表只能有一个,而非聚集索引一个表可以存在多个
2.聚集索引存储记录是物理上连续存在,而非聚集索引是逻辑上的连续,物理存储并不连续
3.聚集索引:物理存储按照索引排序;聚集索引是一种索引组织形式,索引的键值逻辑顺序决定了表数据行的物理存储顺序。
4.非聚集索引:物理存储不按照索引排序;非聚集索引则就是普通索引了,仅仅只是对数据列创建相应的索引,不影响整个表的物理存储顺序。
5.索引是通过二叉树的数据结构来描述的,我们可以这么理解聚簇索引:索引的叶节点就是数据节点。而非聚簇索引的叶节点仍然是索引节点,只不过有一个指针指向对应的数据块。

优势与缺点:
聚集索引插入数据时速度要慢(时间花费在“物理存储的排序”上,也就是首先要找到位置然后插入),查询数据比非聚集数据的速度快。

四、何时使用聚集索引或非聚集索引
动作描述    使用聚集索引    使用非聚集索引
列经常被分组排序    应    应
返回某范围内的数据    应    不应
一个或极少不同值    不应    不应
小数目的不同值    应    不应
大数目的不同值    不应    应
频繁更新的列    不应    应
外键列    应    应
主键列    应    应
频繁修改索引列    不应    应
五、总结
1.使用聚集索引的查询效率要比非聚集索引的效率要高,但是如果需要频繁去改变聚集索引的值,写入性能并不高,因为需要移动对应数据的物理位置。
2.非聚集索引在查询的时候可以的话就避免二次查询,这样性能会大幅提升。
3.不是所有的表都适合建立索引,只有数据量大表才适合建立索引,且建立在选择性高的列上面性能会更好。
CREATE CLUSTER INDEX index_name
ON table_name(column_name1,column_name2,...);

.net资源回收

 

垃圾回收机制的定义
在进行.NET开发时,我们使用了许多对象。一些对象是非常大的,使用完毕后需要被销毁。对于这些对象,我们需要手动释放它们所占用的内存。但是,在有些情况下,我们可能会忘记释放内存,这会导致内存泄漏,影响程序的性能。此时垃圾回收机制就派上用场了。它可以自动地释放不再被程序使用的对象所占用的内存,从而避免内存泄漏。

垃圾回收机制的运作原理
垃圾回收机制的运作原理可以分为三个步骤:

第一步:标记
在第一步中,垃圾回收器会标记所有被引用的对象。一个对象被引用的情况可以是它被分配给了一个变量,或者它是另一个对象的属性或数组元素。这样,所有被引用的对象就被标记为“存活”的对象。

第二步:清除
在第二步中,垃圾回收器会清除所有未被标记为“存活”的对象。这些未被标记的对象是不再被程序所使用的对象,它们所占用的内存将被释放。

第三步:压缩
在第三步中,垃圾回收器会将所有“存活”的对象移动到内存的一端,然后压缩所有“存活”的对象,从而使内存空间连续。这样,内存中的碎片就被减少了,可以更好地利用内存。

垃圾回收机制的优点
垃圾回收机制有以下几个优点:

自动释放内存,避免内存泄漏。

减少手动内存管理的工作量。

增强程序的安全性,避免因为内存泄漏导致的程序崩溃。

总之,.NET的垃圾回收机制是一个非常重要的特性,它可以帮助我们更好地管理内存,提高程序的性能。当然,如果我们想要写出高效的.NET程序,我们需要了解垃圾回收机制的原理,从而更好地利用.NET的特性。

 

class: IDisposable
xxx.Dispose()

 

 

如何阻止回收

1. 用static关键字
2. GCSettings.LatencyMode that can be set to LowLatency https://learn.microsoft.com/en-us/dotnet/api/system.runtime.gcsettings.latencymode?view=net-7.0&redirectedfrom=MSDN#System_Runtime_GCSettings_LatencyMode
public static System.Runtime.GCLatencyMode LatencyMode { get; set; }

 


序列化

序列化最终的目的是为了对象可以跨平台存储和进行网络传输,而我们进行跨平台存储和网络传输的方式就是 IO,而 IO 支持的数据格式就是字节数组
Json JsonSerializer JsonSerializerOptions
[Serializable]
public class MyObject {
  public int n1 = 0;
  public int n2 = 0;
  public String str = null;
}

MyObject obj = new MyObject();
obj.n1 = 1;
obj.n2 = 24;
obj.str = "Some String";
IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None);
formatter.Serialize(stream, obj);
stream.Close();

IFormatter formatter = new BinaryFormatter();
Stream stream = new FileStream("MyFile.bin", FileMode.Open, FileAccess.Read, FileShare.Read);
MyObject obj = (MyObject) formatter.Deserialize(stream);
stream.Close();

// Here's the proof.
Console.WriteLine("n1: {0}", obj.n1);
Console.WriteLine("n2: {0}", obj.n2);
Console.WriteLine("str: {0}", obj.str);
private void SerializeDataSet(string filename)
{
    XmlSerializer ser = new XmlSerializer(typeof(DataSet));

    // Creates a DataSet; adds a table, column, and ten rows.
    DataSet ds = new DataSet("myDataSet");
    DataTable t = new DataTable("table1");
    DataColumn c = new DataColumn("thing");
    t.Columns.Add(c);
    ds.Tables.Add(t);
    DataRow r;

    for (int i = 0; i < 10; i++) {
        r = t.NewRow();
        r[0] = "Thing " + i;
        t.Rows.Add(r);
    }

    TextWriter writer = new StreamWriter(filename);
    ser.Serialize(writer, ds);
    writer.Close();
}

private void SerializeElement(string filename)
{
    XmlSerializer ser = new XmlSerializer(typeof(XmlElement));
    XmlElement myElement = new XmlDocument().CreateElement("MyElement", "ns");
    myElement.InnerText = "Hello World";
    TextWriter writer = new StreamWriter(filename);
    ser.Serialize(writer, myElement);
    writer.Close();
}

private void SerializeNode(string filename)
{
    XmlSerializer ser = new XmlSerializer(typeof(XmlNode));
    XmlNode myNode = new XmlDocument().
    CreateNode(XmlNodeType.Element, "MyNode", "ns");
    myNode.InnerText = "Hello Node";
    TextWriter writer = new StreamWriter(filename);
    ser.Serialize(writer, myNode);
    writer.Close();
}

 


Linq

语言集成查询(英语:Language Integrated Query,缩写:LINQ),发音"link",是微软的一项技术,新增一种自然查询的SQL语法到.NET Framework的编程语言中,当前可支持C#以及Visual Basic .NET语言。2007年11月19日随.NET Framework 3.5发布了LINQ技术。
包括LINQ to Objects、LINQ to SQL、LINQ to Datasets、LINQ to Entities、LINQ to Data Source、LINQ to XML/XSD等。

lambda和Linq区别

 

lambda是匿名函数,而linq是一种语言集成查询
C#的Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。语法如下:
1
(object argOne, object argTwo) => {; /*Your statement goes here*/}
函数体多于一条语句的可用大括号括起。
类型
可以将此表达式分配给委托类型,如下所示:
1
2
3
delegate int del(int i);
del myDelegate=x=>{return x*x;};
int j = myDelegate(5); //j=25
创建表达式目录树类型:
1
2
3
using System.Linq.Expressions;
//...
Expression <del>=x=>x*x;
=> 运算符具有与赋值运算符 (=) 相同的优先级,并且是右结合运算符。
Lambda 用在基于方法的 LINQ 查询中,作为诸如 Where 和 Where 等标准查询运算符方法的参数。
使用基于方法的语法在 Enumerable 类中调用 Where 方法时(像在 LINQ to Objects 和 LINQ to XML 中那样),参数是委托类型 System..::.Func<(Of <(T, TResult>)>)。使用 Lambda 表达式创建委托最为方便。例如,当您在 System.Linq..::.Queryable 类中调用相同的方法时(像在 LINQ to SQL 中那样),则参数类型是 System.Linq.Expressions..::.Expression<Func>,其中 Func 是包含至多五个输入参数的任何 Func 委托。同样,Lambda 表达式只是一种用于构造表达式目录树的非常简练的方式。尽管事实上通过 Lambda 创建的对象的类型是不同的,但 Lambda 使得 Where 调用看起来类似。
在前面的示例中,请注意委托签名具有一个 int 类型的隐式类型输入参数,并返回 int。可以将 Lambda 表达式转换为该类型的委托,因为该表达式也具有一个输入参数 (x),以及一个编译器可隐式转换为 int 类型的返回值。(以下几节中将对类型推理进行详细讨论。)使用输入参数 5 调用委托时,它将返回结果 25。
在 is 或 as 运算符的左侧不允许使用 Lambda。
适用于匿名方法的所有限制也适用于 Lambda 表达式。有关更多信息,请参见匿名方法(C# 编程指南)。
 

特殊

下列规则适用于 Lambda 表达式中的变量范围:
捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。
外部方法中看不到 Lambda 表达式内引入的变量。
Lambda 表达式无法从封闭方法中直接捕获 ref 或 out 参数。
Lambda 表达式中的返回语句不会导致封闭方法返回。
Lambda 表达式不能包含其目标位于所包含匿名函数主体外部或内部的 goto 语句、break 语句或 continue 语句。
Lambda表达式的本质是“匿名方法”,即当编译我们的程序代码时,“编译器”会自动将“Lambda表达式”转换为“匿名方法”,如下例:
1
2
3
string[] names={"agen","balen","coure","apple"};
string[] findNameA=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
string[] findNameB=Array.FindAll<string>(names,v=>v.StartsWith("a"));
上面中两个FindAll方法的反编译代码如下:
1
2
string[] findNameA=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
string[] findNameB=Array.FindAll<string>(names,delegate(string v){return v.StartsWith("a");});
从而可以知道“Lambda表达式”与“匿名方法”是可以划上等号的,只不过使用“Lambda表达式”输写代码看上去更直观漂亮,不是吗?
Lambda表达式的语法格式:
参数列表 => 语句或语句块 [1] 
其中“参数列”中可包含任意个参数(与委托对应),如果参数列中有0个或1个以上参数,则必须使用括号括住参数列,如下:
1
2
3
4
5
6
7
8
9
x => x + 1                              // Implicitly typed, expression body
x => { return x + 1; }                  // Implicitly typed, statement body
(int x) => x + 1                        // Explicitly typed, expression body
(int x) => { return x + 1; }            // Explicitly typed, statement body
(x, y) => x * y                         // Multiple parameters
() => Console.WriteLine()               // No parameters
async (t1,t2) => await t1 + await t2    // Async
delegate (int x) { return x + 1; }      // Anonymous method expression
delegate return 1 + 1; }              // Parameter list omitted
如果“语句或语句块”有返回值时,如果只有一条语句则可以不输写“return”语句,编译器会自动处理,否则必须加上,如下示例:
“Lambda表达式”是委托的实现方法,所以必须遵循以下规则:
1)“Lambda表达式”的参数数量必须和“委托”的参数数量相同;
2)如果“委托”的参数中包括有ref或out修饰符,则“Lambda表达式”的参数列中也必须包括有修饰符;
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Test
{
    delegate int AddHandler(int x,int y);
    static void Print(AddHandler add);
    {
        Console.Write(add(1, 3));
    }
    static void Main(string[] args)
    {
        Print((x,y) => x+y);
        Print((x,y) => {int v=x*10; return y+v;});
        Console.ReadKey();
    }
}
注: 如果包括有修饰符,则“Lambda表达式”中的参数列中也必须加上参数的类型
3)如果“委托”有返回类型,则“Lambda表达式”的“语句或语句块”中也必须返回相同类型的数据;
4)如果“委托”有几种数据类型格式而在“Lambda表达式”中“编译器”无法推断具体数据类型时,则必须手动明确数据类型。
例子:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Test
{
    delegate AddHandler<T> (Tx, Ty);
 
    static void Print(AddHandler<int> test)
    {
        Console.WriteLine("int type:{0}",test(1, 2));
    }
    static void Print(AddHandler<double> test)
    {
        Console.WriteLine("doubletype:{0}",test(1d, 2d));
    }
    static void Main(string[] args)
    {
        Print((x, y) => x+y);
        Console.ReadKey();
    }
}
当我们编译以下代码时,编译器将会显示以下错误信息
1
2
3
在以下方法或属性之间的调用不明确:
"ConsoleApplication1.Test.Print(ConsoleApplication1.Test.AddHandler<int>)"
和"ConsoleApplication1.Test.Print(ConsoleApplication1.Test.AddHandler<double>)"
所以我们必须明确数据类型给编译器,如下:
1
Print((int x, int y) => x+y);
这样我们的代码就能编译通过了。

 

工厂模式,抽象工厂,命令模式

 

工厂模式
官方:工厂方法模式定义一个创建对象的接口,让子类决定实例化那个类
理解:在简单工厂模式的基础上,对创建工厂也进行抽象,使得一个工厂只能创建一个一种类型产品

  

抽象工厂模式:核心工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节。

  

官方:命令模式是一个行为设计模式,它可将请求转换为一个包含与请求相关的所有信息的独立对象。该转换让你能根据不同的请求将方法参数化、延迟请求执行或将其放入队列中,且能实现可撤销操作。
理解:通过将命令操作信息装置到一个对象中,去执行调用具体的Receiver对象,实现解耦
命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命令的责任和执行命令的责任分割开,委派给不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得请求的一方不必知道接收请求的一方的接口,更不必知道请求是怎么被接收,以及操作是否执行,何时被执行以及是怎么被执行的。系统支持命令的撤消。

  

求都超过某分数的名字(SQL)

+------+-------+--------+
| name | calss |  score |
+------+-------+--------+
| 张三  | 语文  |    12   |
| 张三  | 英语  |    80   |
| 张三  | 数学  |    12   |
| 李四  | 语文  |    81   |
| 李四  | 数学  |    86   |
| 李四  | 英语  |    86   |
| 王五  | 语文  |    12   |
| 王五  | 数学  |    90   |
| 赵六  | 语文  |    90   |
| 田七  | 语文  |    90   |
+------+------+----------+
select name, class, score
from table
where name in (
select t.name
from table t
group by t.name
having min(t.score)>=80) 

 

select 
	distinct name 
from score 
where name not in (
		select name from score where score < 80
)

 

SELECT S.name
FROM Student S
GROUP BY S.name Having MIN(S.score)>=80

 

找到所有子节点

用迭代函数

微服务是什么

 

一种软件开发技术- 面向服务的体系结构(SOA)架构样式的一种变体,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。
每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够独立地部署到生产环境、类生产环境等。
另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据上下文,选择合适的语言、工具对其进行构建。

 

restAPI和传统的区别

 

REST API 是一种用于构建 Web 服务的架构风格。REST代表“Representational State Transfer”,它强调使用 HTTP 协议进行通信,利用 HTTP 的各种方法来访问和操作资源。
通俗来说,REST API 是一种规范,用于在客户端和服务器之间传递数据。它提供了一组规则,确保客户端和服务器之间的通信是一致且可靠的。
REST API 使得不同的应用程序之间可以共享数据,并且简化了开发过程。
与一般 API 相比,REST API 具有以下几个方面的区别:
REST API 是基于 HTTP 协议的,而其他 API 可以使用其他协议(如 SOAP)。
REST API 强调资源和方法,而其他API可能使用其他方式来描述其功能和实现。
REST API 使用标准的HTTP方法(如 GET、POST、PUT 和 DELETE)来执行操作,而其他 API 可能使用自定义方法。
POST:操作不是安全的,每次请求都会创建资源。POST,Add。PUT,Update。
HTTP协议规定,POST方法修改资源状态时,URL指示的是该资源的父级资源,待修改资源的ID信息在请求体中携带。而PUT方法修改资源状态时,URL直接指示待修改资源。
REST API 具有良好的可扩展性和可维护性,因为它使用简单的 URL 和标准 HTTP 方法来访问资源。
总之,REST API 是一种简单、轻量级、灵活且可扩展的方式,用于构建 Web 服务。
取用方便,维护方便,与微服务配合使用效果更好。

 

Image在docker里面什么意思

docker生成的镜像文件
docker的三大核心概念是:1.docker镜像(Image);2. docker容器(container);3. docker仓库(repository)。镜像可以理解为处于静态的只读文件,它是创建容器的先决条件,即容器是镜像的运行实体。而仓库的作用则是存储和分发镜像。

 

反射是什么

反射是C#语言中的一种机制,它允许程序在运行时动态地获取类型信息、创建实例、调用成员方法/字段等。通过反射,程序可以探知其它程序集中的类型和成员的详细信息,并且能够在运行时根据这些信息来操作这些类型和成员。

反射API主要由System.Reflection命名空间提供,其中包含一些核心类:Type、ConstructorInfo、MethodInfo、PropertyInfo、FieldInfo等。
using System;
using System.Reflection;
 
namespace ReflectionDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // Step 1 - 获取类型信息
            Type personType = typeof(Person);
 
            // Step 2 - 创建类型实例
            object person = Activator.CreateInstance(personType);
 
            // Step 3 - 调用类型方法/属性/字段等成员
            personType.GetProperty("Name").SetValue(person, "Tom");
            personType.GetProperty("Age").SetValue(person, 20);
 
            MethodInfo sayHelloMethod = personType.GetMethod("SayHello");
            sayHelloMethod.Invoke(person, null);
 
            Console.ReadKey();
        }
    }
}

委托和事务 

委托,就是将函数作为参数传递到方法中。委托可以引用方法,并且可以通过委托来调用其他方法。
事务,就是该委托方法类型的字段

 

class Recon
        {
            public delegate void EnemySpottedEventHandler(string message, Enemy enemy);
            public event EnemySpottedEventHandler EnemySpotted;
            public void Report(Enemy enemy)
            {
                EnemySpotted?.Invoke("Attention! Enemy spotted!", enemy);
            }
        }

        class Sniper
        {
            private void ListenToRecon(Recon recon)
            {
                recon.EnemySpotted += OnEnemySpotted;
            }

            private void OnEnemySpotted(string message, Enemy enemy)
            {
                AimAt(enemy);
            }
        }

 

using System;
using System.IO;

namespace DelegateAppl
{
   class PrintString
   {
      static FileStream fs;
      static StreamWriter sw;
      // 委托声明
      public delegate void printString(string s);

      // 该方法打印到控制台
      public static void WriteToScreen(string str)
      {
         Console.WriteLine("The String is: {0}", str);
      }
      // 该方法打印到文件
      public static void WriteToFile(string s)
      {
         fs = new FileStream("c:\\message.txt", FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      // 该方法把委托作为参数,并使用它调用方法
      public static void sendString(printString ps)
      {
         ps("Hello World");
      }
      static void Main(string[] args)
      {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}

 

多线程

using System;
using System.Threading;

namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {

                Console.WriteLine("Child thread starts");
                // 计数到 10
                for (int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Child Thread Completed");

            }
            catch (ThreadAbortException e)
            {
                Console.WriteLine("Thread Abort Exception");
            }
            finally
            {
                Console.WriteLine("Couldn't catch the Thread Exception");
            }

        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("In Main: Creating the Child thread");
            Thread childThread = new Thread(childref);
            childThread.Start();
            // 停止主线程一段时间
            Thread.Sleep(2000);
            // 现在中止子线程
            Console.WriteLine("In Main: Aborting the Child thread");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

值类型和引用类型

 

值类型的变量直接存储数据,而引用类型的变量持有的是数据的引用,数据存储在数据堆中。

  值类型(value type):byteshortintlongfloatdoubledecimalcharboolstruct 统称为值类型。值类型变量声明后,不管是否已经赋值,编译器为其分配内存。

引用类型(reference type):string 和 class统称为引用类型。当声明一个类时,只在栈中分配一小片内存用于容纳一个地址,而此时并没有为其分配堆上的内存空间。当使用 new 创建一个类的实例时,分配堆上的空间,并把堆上空间的地址保存到栈上分配的小片空间中。

值类型的实例通常是在线程栈上分配的(静态分配),但是在某些情形下可以存储在堆中。引用类型的对象总是在进程堆中分配(动态分配)。

C#的值类型包括:结构体(数值类型、bool型、用户定义的结构体),枚举,可空类型。
C#的引用类型包括:数组,用户定义的类、接口、委托,object,字符串。

 

接口和抽象对象 

1. 抽象类是继承,接口是实现
2. 抽象类可以包含非抽象方法,接口的方法是抽象的待实现
3. 类可以实现多个接口,只能继承一个抽象类
4. 抽象类可以有结构函数,而接口不能有结构函数
5. 接口用于定义一组操作,表示一种能力或行为,这是对行为的抽象抽象类用于定义一个基本类别,提供一些默认的行为和属性,这是抽象类别

 

wcf

Windows通讯开发平台(Windows Communication Foundation,简称WCF)是由微软开发的一系列支持数据通信的应用程序框架,可以翻译为Windows通讯开发平台。
整合了原有的windows通讯的 .net Remoting,WebService,Socket的机制,并融合有HTTP和FTP的相关技术。
简单的归结为四大部分
1.网络服务的协议,即用什么网络协议开放客户端接入。
2.业务服务的协议,即声明服务提供哪些业务。
3.数据类型声明,即对客户端与服务器端通信的数据部分进行一致化。
4.传输安全性相关的定义。

 

mvc

M=model,V=View,C=Controller

 


为什么用存储过程

  1.存储过程只在创造时进行编译,以后每次执行存储过程都不需再重新编译,而一般 SQL 语句每执行一次就编译一次,所以使用存储过程可提高数据库执行速度。
  2.当对数据库进行复杂操作时(如对多个表进行 Update,Insert,Query,Delete 时),可将此复杂操作用存储过程封装起来与数据库提供的事务处理结合一起使用。这些操作,如果用程序来完成,就变成了一条条的 SQL 语句,可能要多次连接数据库。而换成存储过程,只需要连接一次数据库就可以了。
  3.存储过程可以重复使用,可减少数据库开发人员的工作量。
  4.安全性高,可设定只有某此用户才具有对指定存储过程的使用权

 


await做了什么

await做了什么
等待,执行 当前执行代码的线程应该被释放掉,从而使你的代码变为异步的。这意味着,从一个普通的同步方法的角度来看,你的方法应该返回。 当你await的Task结束后,你的方法应该从上次返回的地方继续执行,就像它之前不曾返回了一样 Async async方法是同步的,除非需要使用await调用异步方法时,才会变为异步 标记为async的方法只有在遇到了第一个await才会暂停,有时给await的task已经完成任务了,这时就不需要暂停了。
1.task是通过task.FromResult方法创建完成的 2.标记为async的方法,但不会运行到await,这个方法返回的task 3.task真的执行了异步操作,但是现在已经结束了 4.标记为async的方法,当运行到await时返回的task,此时task已经结束了

 


http protocol

HTTP=Hyper Text Transfer Protocol , 超文本传输协议

 


赋值null占用内存吗,是否被回收

不会。比如创建了一个桶 赋值只是清空了里面的对象。但是桶依然还存在。在到该回收的时候自然就回收了

 


堆和栈的区别

  堆 stack 栈 heap
内存分配方式 堆则是由程序员手动申请和释放的,通常用于存储程序中需要动态分配的内存(如动态数组、对象等) 由程序自动创建和释放的,通常用于存储函数调用时的临时变量、函数的返回地址等信息
内存管理方式 堆的内存管理则需要程序员自行负责,使用完毕后必须手动释放,否则会导致内存泄漏或其他问题 栈中的内存管理是由系统自动完成的,程序员不需要过多考虑内存的分配和释放问题
内存大小 堆用于存储较大的数据结构,大小一般比栈要大得多,可以动态扩展内存空间。但是,因为堆需要手动管理内存,如果不及时释放,会导致内存泄漏,进而影响系统性能 栈的容量较小,一般只有几百KB到几MB的空间,具体容量由操作系统和编译器决定
访问速度

访问堆中的数据需要通过指针进行间接访问,会造成一定的时间损耗

堆则需要考虑多线程并发访问时的同步和互斥机制

栈的内存分配是系统自动完成的,所以访问速度相对堆更快。栈中的数据直接存放在系统内存中

在多线程环境下,由于栈的线程独享,所以不会发生竞争问题

应用场景 堆适合用于存储需要动态分配和管理的数据结构,如动态数组、字符串、对象 栈适合用于存储局部变量和函数调用,主要用于内存的临时分配


.net core中如何实现EF

 1 https://learn.microsoft.com/zh-cn/ef/core/
 2 
 3 model
 4 using System.Collections.Generic;
 5 using Microsoft.EntityFrameworkCore;
 6 
 7 namespace Intro;
 8 
 9 public class BloggingContext : DbContext
10 {
11     public DbSet<Blog> Blogs { get; set; }
12     public DbSet<Post> Posts { get; set; }
13 
14     protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
15     {
16         optionsBuilder.UseSqlServer(
17             @"Server=(localdb)\mssqllocaldb;Database=Blogging;Trusted_Connection=True");
18     }
19 }
20 
21 public class Blog
22 {
23     public int BlogId { get; set; }
24     public string Url { get; set; }
25     public int Rating { get; set; }
26     public List<Post> Posts { get; set; }
27 }
28 
29 public class Post
30 {
31     public int PostId { get; set; }
32     public string Title { get; set; }
33     public string Content { get; set; }
34 
35     public int BlogId { get; set; }
36     public Blog Blog { get; set; }
37 }
38 
39 Query
40 using (var db = new BloggingContext())
41 {
42     var blogs = db.Blogs
43         .Where(b => b.Rating > 3)
44         .OrderBy(b => b.Url)
45         .ToList();
46 }
47 
48 Save
49 using (var db = new BloggingContext())
50 {
51     var blog = new Blog { Url = "http://sample.com" };
52     db.Blogs.Add(blog);
53     db.SaveChanges();
54 }

.net core序列化和.net framework的区别?

 

.net core
停止在代码中使用 BinaryFormatter。 此时,考虑使用 JsonSerializer 或 XmlSerializer。 
.net framework
System.Runtime.Serialization
IFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, obj);

 

  

 

.net core数据请求和.net的区别

https://learn.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/request-response?view=aspnetcore-7.0
.net
private async Task<List<string>> GetListOfStringsFromStreamMoreEfficient(Stream requestBody)
{
    StringBuilder builder = new StringBuilder();
    byte[] buffer = ArrayPool<byte>.Shared.Rent(4096);
    List<string> results = new List<string>();

    while (true)
    {
        var bytesRemaining = await requestBody.ReadAsync(buffer, offset: 0, buffer.Length);

        if (bytesRemaining == 0)
        {
            results.Add(builder.ToString());
            break;
        }

        // Instead of adding the entire buffer into the StringBuilder
        // only add the remainder after the last \n in the array.
        var prevIndex = 0;
        int index;
        while (true)
        {
            index = Array.IndexOf(buffer, (byte)'\n', prevIndex);
            if (index == -1)
            {
                break;
            }

            var encodedString = Encoding.UTF8.GetString(buffer, prevIndex, index - prevIndex);

            if (builder.Length > 0)
            {
                // If there was a remainder in the string buffer, include it in the next string.
                results.Add(builder.Append(encodedString).ToString());
                builder.Clear();
            }
            else
            {
                results.Add(encodedString);
            }

            // Skip past last \n
            prevIndex = index + 1;
        }

        var remainingString = Encoding.UTF8.GetString(buffer, prevIndex, bytesRemaining - prevIndex);
        builder.Append(remainingString);
    }

    ArrayPool<byte>.Shared.Return(buffer);

    return results;
}

上面的此示例:

不在 StringBuilder 中缓冲整个请求正文(除非没有任何换行符)。
不在字符串上调用 Split。
然而,仍然存在一些问题:

如果换行符稀疏,则大部分请求正文都在字符串中进行缓冲。
该代码会继续创建字符串 (remainingString) 并将它们添加到字符串缓冲区这将导致额外的分配。
这些问题是可修复的,但代码逐渐变得复杂,几乎没有什么改进。 管道提供了一种以最低的代码复杂性解决这些问题的方法。

.net core
private async Task<List<string>> GetListOfStringFromPipe(PipeReader reader)
{
    List<string> results = new List<string>();

    while (true)
    {
        ReadResult readResult = await reader.ReadAsync();
        var buffer = readResult.Buffer;

        SequencePosition? position = null;

        do
        {
            // Look for a EOL in the buffer
            position = buffer.PositionOf((byte)'\n');

            if (position != null)
            {
                var readOnlySequence = buffer.Slice(0, position.Value);
                AddStringToList(results, in readOnlySequence);

                // Skip the line + the \n character (basically position)
                buffer = buffer.Slice(buffer.GetPosition(1, position.Value));
            }
        }
        while (position != null);


        if (readResult.IsCompleted && buffer.Length > 0)
        {
            AddStringToList(results, in buffer);
        }

        reader.AdvanceTo(buffer.Start, buffer.End);

        // At this point, buffer will be updated to point one byte after the last
        // \n character.
        if (readResult.IsCompleted)
        {
            break;
        }
    }

    return results;
}

private static void AddStringToList(List<string> results, in ReadOnlySequence<byte> readOnlySequence)
{
    // Separate method because Span/ReadOnlySpan cannot be used in async methods
    ReadOnlySpan<byte> span = readOnlySequence.IsSingleSegment ? readOnlySequence.First.Span : readOnlySequence.ToArray().AsSpan();
    results.Add(Encoding.UTF8.GetString(span));
}
此示例解决了流实现中的许多问题:

不需要字符串缓冲区,因为 PipeReader 会处理未使用的字节编码后的字符串将直接添加到返回的字符串列表。
除了 ToArray 调用以及字符串使用的内存,创建字符串时无需分配。

  


race condition

Race condition

从定义来说,race condition是代码中一些执行结果取决于其执行的相对时间或者多线程交错执行的判断条件。它的结果是不可预测的。如何一个程序中不存在race condition,那么它就是线程安全的(thread-safe)

Race condition的两个模式

Check-Then-Act

Race condition有两个模式,第一个就是上面的转账的例子,属于Check-Then-Act模式,这类模式通常是一个流程中有一个检查环节,通过检查的结果再决定后续怎么走。

Read-Modify-Write

Read-Modify-Write是race condtion的第二个模式。在大多数编程语言中,对一个变量的修改通常分为读取,修改,写入三个步骤。问题通常是对变量的并发的读取修改(至少有一个修改,纯读取是没问题的)引起的。

如何避免race condition

1.避免使用共享变量

在多线程环境中,race condtion的出现往往伴随着共享变量,如上面例子中的账户余额和count变量,都可以被多个线程读取操作,那么避免问题发生最简单直接的办法就是避免使用共享变量。可以使用不可变对象或者线程本地对象(例如java中的threadlocal)。

2.使用同步或者原子操作

使用同步可以避免race condition的问题,但是线程同步往往伴随很多同步的性能开销,还可能导致死锁。两个办法是使用原子操作,例如java中的提供的原子类。

 

 

虚函数

那些被virtual关键字修饰的成员函数,就是虚函数。虚函数的作用,用专业术语来解释就是实现多态性(Polymorphism),多态性是将接口与实现进行分离;用形象的语言来解释就是实现以共同的方法,但因个体差异,而采用不同的策略。

#include<iostream>
using namespace std;
class A{//虚函数示例代码2
    public:
        virtual void fun(){cout<<"A::fun"<<endl;}
        virtual void fun2(){cout<<"A::fun2"<<endl;}
};
class B : public A{
    public:
        void fun(){cout<<"B::fun"<<endl;}
        void fun2(){cout<<"B::fun2"<<endl;}
};//end//虚函数示例代码2
int main()
{
    void(A::*fun)();//定义一个函数指针
    A *p=new B;
    fun=&A::fun;
    (p->*fun)();
    fun=&A::fun2;
    (p->*fun)();
    delete p;
    system("pause");
    return 0;
}

 


字典中如何查找

 

1. ContainsValue() 方法
2. LINQ 查询

 

Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("key1", "value1");
dict.Add("key2", "value2");
bool containsValue = dict.ContainsValue("value2");
if (containsValue)
{
    Console.WriteLine("Dictionary contains the value");
}
else
{
    Console.WriteLine("Dictionary does not contain the value");
}
Dictionary<string, string> dict = new Dictionary<string, string>();
dict.Add("key1", "value1");
dict.Add("key2", "value2");
bool containsValue = dict.Any(x => x.Value == "value2");
if (containsValue)
{
    Console.WriteLine("Dictionary contains the value");
}
else
{
    Console.WriteLine("Dictionary does not contain the value");
}

 

授权登录

https://blog.csdn.net/lemon_TT/article/details/127500409
OAuth(Open Authorization)是一个关于授权(authorization)的开放网络标准,允许用户授权第三方 应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他 们数据的所有内容。

优点


更安全,客户端不接触用户密码,服务器端更易集中保护

广泛传播并被持续采用

短寿命和封装的token

资源服务器和授权服务器解耦

集中式授权,简化客户端

HTTP/JSON友好,易于请求和传递token

考虑多种客户端架构场景

客户可以具有不同的信任级别


缺点


协议框架太宽泛,造成各种实现的兼容性和互操作性差

不是一个认证协议,本身并不能告诉你任何用户信息
————————————————

不管哪一种授权方式,第三方应用申请令牌之前,都必须先到系统备案,说明自己的身份,然后会拿到两个身份识别码:客户端 ID(client ID)和客户端密钥(client secret)。这是为了防止令牌被滥用,没有备案过的第三方应用,是不会拿到令牌的

Authorization Code(授权码模式):正宗的OAuth2的授权模式,客户端先将用户导向认证服务器,认证用户成功后获取授权码,然后进行授权,最后根据授权码获取访问令牌;

Implicit(隐藏式):和授权码模式相比,取消了获取授权码的过程,直接获取访问令牌;

Password(密码模式):客户端直接向用户获取用户名和密码,之后向认证服务器获取访问令牌;

Client Credentials(客户端凭证模式):客户端直接通过客户端认证(比如client_id和client_secret)从认证服务器获取访问令牌。

一般来说,授权码模式和密码模式是两种常用的授权模式
————————————————

 

 


依赖注入时效性

依赖注入一共有三种生命周期

AddTransient(瞬时) 作用: 每次请求,都获取一个新的实例。即使同一个请求获取多次也会是不同的实例(只要请求new 新的)
瞬时,就是没有生存期,每次依赖注入时就生成一个新的实例。

AddScoped(作用域)作用: 每次请求,都获取一个新的实例。同一个请求获取多次会得到相同的实例
在一个请求作用域中,第一次会生成一个新的实例,当当前请求作用域结束时,该实例一起被销毁。

AddSingleton(单例)作用:每次都获取同一个实例 (比如:帮助类的内容)
单例,会一直存在,与应用有同样的寿命。仅在第一次依赖注入系统获取服务对象时建立一个新的实例,之后每次都是调用该实例。
依赖注入的三种方式
1. 接口注入
 在接口中定义要注入的信息,实际使用时,实现该接口完成注入。
2. set注入
 在被注入的类中定义一个set方法,并在参数中定义需要注入的内容。
3. 构造注入
 在定义构造方法时,在参数中定义需要注入的内容。

 

services.AddScoped<ISchema<T>, GraphQLSchema<T>>();
services.AddSingleton<IDocumentExecuter, GraphQLDocumentExecutor>();
if (!services.Any(i => i.ServiceType == typeof(IGraphQLServiceProvider)))
{
    services.AddTransient<IGraphQLServiceProvider, GraphQLServiceProvider>();
}

  

构造器注入
public class MyClass 
{ 
    private IMyInterFace _myinterface; 
    public MyClass (IMyInterFace myinterface) 
    { 
        this._myinterface = myinterface; 
    } 
} 

Setter注入
private IMyInterFace _myinterface; 
public IMyInterFace myinterface
{ 
    get { return _myinterface; } 
    set { _myinterface = value; } 
} 

接口注入
public interface IMyInterFaceCace
{
    IMyInterFace myinterfacce { get; set; }
}

class MyClass : IMyInterFaceCace
{
    private IMyInterFace _myinterfacce;
    public IMyInterFace myinterfacce
    {
        get { return _myinterfacce; }
        set { _myinterfacce = value; }
    }
}

  


冒泡排序

冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。 
它重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。
走访元素的工作是重复地进行直到没有相邻元素需要交换,也就是说该元素列已经排序完成。 
这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端(升序或降序排列),
就如同碳酸饮料中二氧化碳的气泡最终会上浮到顶端一样,故名“冒泡排序”。

  

快速排序

1.分解:数组arr[left,right]被分为两个子数组arr[left,pivot-1]和arr[pivot+1,right] 使得arr[left,pivot-1]中的元素都小于等于arr[pivot],而arr[pivot+1,right] 中的元素都大于等于arr[pivot]。

2.解决:通过递归调用快速排序,对两个子数组arr[left,pivot-1]和arr[pivot+1,right]进行排序。

3.合计:两个子数组合并。

  

sql自增量

AUTO INCREMENT字段   
因为在一张表中主键中的数据是不可重复的,有些时候,我们希望主键的数据是自动生成的且唯一的,
这时候使用AUTO INCREMENT字段就显的方便了很多,在定义一张表的同时设置主键为自动增量(Auto-increment)字段,
这样在插入数据的时候就会自动生成一个唯一的数据了   
Auto-increment 会在新记录插入表中时生成一个唯一的数字

 identity(seed, increment)
seed=起始值
increment=增量

  


sql事务4个ACID

ACID,是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:
原子性(atomicity,或称不可分割性)、
一致性(consistency)、
隔离性(isolation,又称独立性)、
持久性(durability)。

  

sql运算符

算术运算符 +(加)、-(减)、*(乘)、/(除)、%(取模,也就是商)。

赋值运算符 “=”(等号)表示赋值,例如:Name=‘王华’

比较运算符 >,<,=,<>,>=,<=

逻辑运算符 逻辑运算符用来对某个条件进行判断,以获得判断的真假,AND,OR,NOT

  


三次握手,断开连接需要几次

4次。
client或server端均可发起关闭,FIN,在对方接受到信号后返回确认ACK。
对方再发起关闭,FIN,我方接收到后,返回确认,ACK。

  

网络:sleep live

using System.Threading;

int sleepfor=1000;
Thread.Sleep(sleepfor);

Monitor.Wait(obj);//使object变成wait状态
Monitor.Pulse(obj);//使object由wait状态被通知唤醒

  

get和post的区别

GET 在浏览器回退时是无害的,而 POST 会再次提交请求。

GET 产生的 URL 地址可以被 Bookmark,而 POST 不可以。

GET 请求会被浏览器主动 cache,而 POST 不会,除非手动设置。

GET 请求只能进行 url 编码,而 POST 支持多种编码方式。

GET 请求参数会被完整保留在浏览器历史记录里,而 POST 中的参数不会被保留。

GET 请求在 URL 中传送的参数是有长度限制的,而 POST 么有。

对参数的数据类型,GET 只接受 ASCII 字符,而 POST 没有限制。

GET 比 POST 更不安全,因为参数直接暴露在 URL 上,所以不能用来传递敏感信息。

GET 参数通过 URL 传递,POST 放在 Request body 中。


对于 GET 方式的请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200(返回数据);
对于 POST,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data,服务器响应 200 ok(返回数据)。

 

sql游标

游标是一组结果集,就是select查询之后返回的所有行数据的集合。游标其实可以理解成一个定义在特定数据集上的指针,我们可以控制这个指针遍历数据集,或者仅仅是指向特定的行。

游标(Cursor)的优点:

是处理数据的一种方法。
它可以定位到结果集中的某一行,对数据进行读写。
也可以移动游标定位到你需要的行中进行数据操作。
是面向集合的数据库管理系统和面向行的程序设计之间的桥梁
作为一个备用方式,当我们穷尽了while循环,子查询,临时表,表变量,自建函数或其他方式仍然无法实现某些查询的时候用游标来实现。
游标(Cursor)的缺点:

游标会吃更多的内存,减少可用的并发,占用宽带,锁定资源还有更多的代码量。
一个完整的游标由5部分组成:

(1)声明游标 (2)打开游标 (3)从一个游标中查找信息 (4)关闭游标 (5)释放游标

  

declare 
 localscore integer;
cursor_score cursor for
	select score from public."ScoreTable";
	go
Begin
	fetch next 
 cursor_score
into @localscore;
go
select @localscore
go
close cursor_score
go
deallocate cursor_score
go
End;

  

dll防止反编译

工具.Net Reactor

  

数据仓库

数据仓库是一个集中式存储库,用于存储结构化数据(数据库表、Excel 工作表)和半结构化数据(XML 文件、网页),以便进行报告和分析。数据从各种源(如销售点系统、业务应用程序和 关系数据库)流入,通常会在到达仓库之前进行清理和标准化。由于数据仓库可以存储大量信息,因此用户可以轻松访问大量历史数据,这些数据可用于数据挖掘、数据可视化和其他形式的商业智能报告。
  1. 确定数据仓库的目标和场景
  2. 收集数据源,包括数据采集工具、数据清洗工具和数据存储工具
  3. 进行数据预处理,去除冗余和错误数据
  4. 构建数据仓库框架,包括数据表、字段、外键等
  5. 设置数据仓库的性能限制,如索引的使用、数据加载速度等
  6. 测试数据仓库并提出完善建议

  

 


 


数据湖

数据仓库

类型

结构化、半结构化、非结构化
关系、非关系

结构化
关系

架构

基于读取的架构

基于写入的架构

格式

原始、未筛选

已处理、已审核

大数据、IoT、社交媒体、流数据

应用程序、业务、事务数据、批处理报告

可伸缩性

轻松缩放,成本低

完成缩放很困难且成本高昂

用户

数据科学家、数据工程师

数据仓库专业人员、业务分析师

用例

机器学习、预测分析、实时分析

核心报告、BI

  

 


从200-500各区间段表示什么意思

 

200-206:服务器成功处理了请求的状态代码,说明网页或资源可以正常访问。
300-307:要完成请求,需要进一步进行操作。通常,这些状态代码是永远重定向的。
4XX:请求可能出错。会妨碍服务器的处理。
500-505:服务器在尝试处理请求时发生内部错误。通常是服务器本身的错误,而不是请求出错。

1**    信息,服务器收到请求,需要请求者继续执行操作
2**    成功,操作被成功接收并处理
3**    重定向,需要进一步的操作以完成请求
4**    客户端错误,请求包含语法错误或无法完成请求
5**    服务器错误,服务器在处理请求的过程中发生了错误

 

  

 

200-206:服务器成功处理了请求的状态代码,说明网页或资源可以正常访问。
200(成功)  服务器已成功处理了请求。通常,这表示服务器提供了请求的网页或资源。
201(已创建)  请求成功且服务器已创建了新的资源。 
202(已接受)  服务器已接受了请求,但尚未对其进行处理。 
203(非授权信息)  服务器已成功处理了请求,但返回了可能来自另一来源的信息。 
204(无内容)  服务器成功处理了请求,但未返回任何内容。 
205(重置内容) 服务器成功处理了请求,但未返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如清除表单内容以输入新内容)。 
206(部分内容)  服务器成功处理了部分 GET 请求。

  

300-307:要完成请求,需要进一步进行操作。通常,这些状态代码是永远重定向的。
300(多种选择)  服务器根据请求可执行多种操作。服务器可根据请求者 来选择一项操作,或提供操作列表供其选择。 
301(永久移动)  请求的网页已被永久移动到新位置。服务器返回此响应时,会自动将请求者转到新位置。应使用此代码通知搜索引擎蜘蛛网页或网站已被永久移动到新位置。 
302(临时移动)  服务器正从不同位置的网页响应请求,请求者应继续使用原有位置来进行以后的请求。服务器会自动将请求者转到不同的位置。但由于搜索引擎会继续抓取原有位置并将其编入索引,因此不应使用此代码来告诉搜索引擎页面或网站已被移动。 
303(查看其他位置) 当请求者应对不同的位置进行单独的 GET 请求以检索响应时,服务器会返回此代码。对于除 HEAD 请求之外的所有请求,服务器会自动转到其他位置。 
304(未修改) 自从上次请求后,请求的网页未被修改过。服务器返回此响应时,不会返回网页内容。
如果网页自请求者上次请求后再也没有更改过,应当将服务器配置为返回此响应。由于服务器可以告诉 搜索引擎自从上次抓取后网页没有更改过,因此可节省带宽和开销。 

305(使用代理) 请求者只能使用代理访问请求的网页。如果服务器返回此响应,那么,服务器还会指明请求者应当使用的代理。 
307(临时重定向)  服务器正从不同位置的网页响应请求,请求者应继续使用原有位置来进行以后的请求。服务器会自动将请求者转到不同的位置。但由于搜索引擎会继续抓取原有位置并将其编入索引,因此不应使用此代码来告诉搜索引擎某个页面或网站已被移动。

  

4XX:请求可能出错。会妨碍服务器的处理。
400(错误请求) 服务器不理解请求的语法。 
401(身份验证错误) 此页要求授权。
403(禁止) 服务器拒绝请求。
404(未找到) 服务器找不到请求的网页。对于服务器上不存在的网页或某些错误的路由会返回此状态码,服务器应该指定错误页面。
405(方法禁用) 禁用请求中指定的方法。
406(不接受) 无法使用请求的内容特性响应请求的网页。 
407(需要代理授权) 此状态码与 401 类似,但指定请求者必须授权使用代理。如果服务器返回此响应,还表示请求者应当使用代理。 
408(请求超时) 服务器等候请求时发生超时。 
409(冲突) 服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,以及两个请求的差异列表。 
410(已删除) 请求的资源永久删除后,服务器返回此响应。该代码与 404(未找到)代码相似,但在资源以前存在而现在不存在的情况下,有时会用来替代 404 代码。如果资源已永久删除,应当使用 301 指定资源的新位置。 
411(需要有效长度) 服务器不接受不含有效内容长度标头字段的请求。 
412(未满足前提条件) 服务器未满足请求者在请求中设置的其中一个前提条件。 
413(请求实体过大) 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 
414(请求的 URI 过长) 请求的 URI(通常为网址)过长,服务器无法处理。不同的浏览器和服务器对URL的长度、大小支持有差异。
415(不支持的媒体类型) 请求的格式不受请求页面的支持。 
416(请求范围不符合要求) 如果页面无法提供请求的范围,则服务器会返回此状态码。 
417(未满足期望值) 服务器未满足"期望"请求标头字段的要求。

  

500-505:服务器在尝试处理请求时发生内部错误。通常是服务器本身的错误,而不是请求出错。
500(服务器内部错误)  服务器遇到错误,无法完成请求。
501(尚未实施) 服务器不具备完成请求的功能。例如,当服务器无法识别请求方法时,服务器可能会返回此代码。
502(错误网关) 服务器作为网关或代理,从上游服务器收到了无效的响应。
503(服务不可用) 目前无法使用服务器(由于超载或进行停机维护)。通常,这只是一种暂时的状态。
504(网关超时)  服务器作为网关或代理,未及时从上游服务器接收请求。
505(HTTP 版本不受支持) 服务器不支持请求中所使用的 HTTP 协议版本。

  


ssrs的log哪里看

开始 SQL Server Management Studio
连接到报表服务器。
右键单击报表服务器名称,然后选择“属性”。
单击 “日志记录” 将此页打开。

  


ssrs生成ide

SQL SERVER 安装集成的 IDE -- BIDS(SQL Server Business Intelligence Development Studio)

  


函数和存储过程区别

一、含义不同

1、存储过程:存储过程是SQL 语句和可选控制流语句的预编译集合,以一个名称存储并作为一个单元处理。

2、函数:是由一个或多个 SQL 语句组成的子程序,可用于封装代码以便重新使用。 函数限制比较多,如不能用临时表,只能用表变量等

二、使用条件不同

1、存储过程:可以在单个存储过程中执行一系列 SQL 语句。而且可以从自己的存储过程内引用其它存储过程,这可以简化一系列复杂语句。

2、函数:自定义函数诸多限制,有许多语句不能使用,许多功能不能实现。函数可以直接引用返回值,用表变量返回记录集。但是,用户定义函数不能用于执行一组修改全局数据库状态的操作。

三、执行方式不同

1、存储过程:存储过程可以返回参数,如记录集,函数只能返回值或者表对象。存储过程的参数有in,out,inout三种,存储过程声明时不需要返回类型。

2、函数:函数参数只有in,而函数需要描述返回类型,且函数中必须包含一个有效的return语句

存储过程是预编译的,执行效率比函数高
存储过程可以不返回任何值,也可以返回多个输出变量,但函数有且必须有一个返回值
存储过程必须单独执行,而函数可以嵌入到其他语句中执行

  


如何限定泛型返回的类型

 

if(typeof(TReturnType) == typeof(int))
{
    var number = (int)returnValue;
    //Validate your output
}

  

单元测试

 

[TestClass]
public class LeetCodeTest
{
 [TestMethod()]
 [ExpectedException(typeof(ArgumentNullException))]
 public void MidianTest()
 {
     LeetCode.Midian(null);
 }

 [TestMethod()]
 [ExpectedException(typeof(ArgumentOutOfRangeException))]
 public void MidianTest1()
 {
     LeetCode.Midian(new List<double>());
 }

 [TestMethod()]
 public void MidianTest2()
 {
     Assert.AreEqual(0.5d, LeetCode.Midian(new List<double>() { 0d, 1d }));
 }
}

 

  

   正常输入:例如字符串的Trim函数,功能是将字符串前后的空格去除,那么正常的输入可以有四类:前面有空格;后面有空格;前后均有空格;前后均无空格。

  边界输入:上例中空字符串可以看作是边界输入,如果输入是一个指针的话,空指针也算是边界输入。再如一个表示年龄的参数,它的有效范围是0-100,那么边界输入有两个:0和100。

  非法输入:非法输入是正常取值范围以外的数据,或使代码不能完成正常功能的输入,如上例中表示年龄的参数,小于0或大于100都是非法输入,再如一个进行文件操作的函数,非法输入可能有:文件不存在;目录不存在;文件正在被其他程序打开;权限错误。

  

 

posted on 2023-08-29 15:18  Riusmary  阅读(12)  评论(0编辑  收藏  举报

导航