当前位置:   article > 正文

C#笔记-基础知识,问答,WPF_wpf xp

wpf xp

UMP,WPF

Universal Windows Platform (UWP) 和 Windows Presentation Foundation (WPF) 是不相同的,虽然都可以做界面,但是 UWP 是一个新的 UI 框架,而且 UWP 是支持很多平台,至少比 WPF 多。

那么UWP 可以使用什么写?

  • xaml 做的 UI 和 C#、VB 写的后台
  • xaml 的 UI 和 C++ Native 写的后台
  • DirectX 的 UI 和 C++ Native 写的后台
  • JavaScript 和 HTML

WPF 可以使用 xaml 做的前台,C#、VB、F#、C++写的后台。

不过需要知道,WPF 的C++ 后台使用的是托管的C++。

那么网上怎么好多小伙伴说 UWP 的性能比 WPF 好?

因为 UWP 的渲染使用的是 DirectComposition 而 WPF 使用的 Desktop Window Manager,请不要在这里和我说 WPF 使用的 DX9 。

虽然 WPF 渲染是通过 Dx9 但是最后显示出来是需要 DWM ,所以上面这样说。

之外,UWP 使用 dot net core 编译出来的是 Native 本地代码,WPF 使用 dot net Framework 编译出来是 IL 代码,需要知道 编译出来 Native 代码的性能是 80% C++非托管。所以代码运行会快很多。

这时不要说 IL 可以针对每个 CPU 做优化,因为 dot net core 编译的代码就是对不同的 CPU 做优化。如果还需要对特殊CPU做优化,我还没找到。

系统支持
因为 WPF 发布的时候还没有 Win7 所以 WPF 是支持 xp 的。但是如果需要支持 xp 就需要使用不大于 .net Framework 4.0 的版本,如果比 4.0 大就无法支持 xp 啦。

需要知道,在 4.5之后 WPF 才修复很多 bug ,提升性能,能不支持 xp 就不要支持 xp。

UWP 发布的时候,因为使用的是 WinRT ,虽然底层和 WPF 一样使用的是 COM 但是添加了很多以前系统不支持的特性。微软为了减少开发或者基于某些考虑,于是UWP不支持以前系统,最低是 win10.

其他
虽然微软说 WPF 是支持触摸的,但是在 4.7 之前的触摸是很差的。所以 WPF 支持鼠标键盘。

但是 UWP 是支持触摸的,鼠标、键盘。

对于 触摸的支持,uwp 是做的很好的,不仅支持了 4.7.1 的指针消息而且还内部支持很多手势。

对于AR的输入,uwp也是支持的。

虽然 WPF 和 UWP 都使用 xaml 做界面,但是渲染是不相同的。 WPF 的渲染都是使用托管代码计算,然后通过通道使用 DirectX 9 渲染。渲染完成给 DWM 选择是否显示。但是 WPF 没有使用 DirectX 9 的性能,所以渲染是比较慢的。听说 WPF 可以使用 dx11 dx12都是使用优化级别是 fl9 。

但是 UWP 的渲染很快,因为他使用DirectComposition直接渲染,使用 DX11 渲染。DirectComposition 是通过集成 DWM 渲染的。组合的图形和动画通过 DirectComposition 构建然后传到 DWM 渲染到屏幕。所以使用 DirectComposition 不需要特殊的渲染框架。而且渲染的代码都是编译本地,比较多使用 DX11 ,但是对于很多硬件都支持 dx12 。

那么 DWM 的作用是什么,实际上从博客可以看到 DWM 实际作用 Windows 组合引擎或合成程序,需要每个窗口把显示的内容给屏外表面或缓冲区,缓冲区是系统给每个顶层窗口分配的,所有的 GDI、D3D、D2D 到先渲染到这里。然后 DWM 决定如何显示,是组合窗口还是做特效,最后再把缓存放到显卡。

WinUI

参考 https://zhuanlan.zhihu.com/p/147499467

尽管WPF已经很完善,UMP看起来也很美好,但是WPF不能跨平台,UMP受限于API和不够完善,目前用的比较多的反而是WPF和xamarin。坏消息是,目前WPF项目开发都停滞不前,更新缓慢。

为解决客户端开发问题,目前,Windows10 1803版本之后,微软开始推WinUI,用来替代UWP和WPF。
功能比较

So, 基于dot Net Core 的WPF 和 WinUI 3 都是很好的期待。

还有一个前途未知的Avalonia

短期以WPF(.net core)和Avalonia项目!

参考链接

dot Net 体系结构

C#运行在公共语言运行库(CLR)下,称为托管代码(managed code).

编译分为几个阶段:

  • 将源代码编译为中间语言(IL)
  • CLR将IL编译为平台专用代码

Microsoft中间语言与Java字节码共享一种理念:他们都是低级语言,语法简单,可以很快转为本地机器码。优点是:平台无关,提高性能和语言互操作性。

ildasm是基于windows的实用程序,可以检查程序集的内容,包含清单和元数据。

共享程序集放在文件系统的一个特定的子目录树中,称为全局程序集缓存GAC。与私有程序集不同,不能简单地把共享程序集复制到对应的文件夹中,而需要专门安装到缓存中,可以用许多NET工具完成这个过程,其中包含对程序集的检查、在程序集缓存中设置一个小的文件夹层次结构,以确保程序集的完整性。

少从开发人员的角度来看,编写托管代码的最大好处是可以使用NET基类库。NET基类是一个内容丰富的托管代码类集合,它可以完成以前要通过Windows API来完成的绝大多数任务。NET基类的一个主要优点是它们非常直观和易用。可以通过WinCV浏览类库中的类,结构,接口和枚举。

核心C#

  • 声明变量
  • 变量的初始化和作用域
  • C++的预定义数据类型
  • 在C#程序中使用条件语句、循环和跳转语旬指定执行流
  • 枚举
  • 名称空间
  • Main()方法
  • 基本的命令行C#编译器选项
  • 使用System.Cosole 执行控制台I/O
  • 使用内部注释和文档编制功能
  • 预处理器指令
  • C#编程的推荐规则和约定
using System;

namespace ConsoleHello
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

C#有两个方法可确保变量在使用前进行了初始化:

  • 变量是类或结构中的字段,如果没有显式初始化,创建这些变量时,其默认值就是O(类和结构在后面讨论)。
  • 方法的局部变量必须在代码中显式初始化,之后才能在语句中使用它们的值。此时,初始化不是在声明该变量时进行的,但编译器会通过方法检查所有可能的路径,如果检测到局部变量在初始化之前就使用了它的值,就会产生错误。

类型推断(type inference)使用var关键字。声明变量的语法有些变化。编译器可以根据变量的初始化值"推断"变量的类型。

C#在变量之间有一个基本的区分,它把在类型级别声明的变量看作字段,而把在方法中声明的变量看作局部变量。如下:

using System;

namespace ConsoleHello
{
    class Program
    {
        static int a = 10;
        static void Main(string[] args)
        {
            int a = 22;
            Console.WriteLine(a);   // 22
            Console.WriteLine(Program.a);  // 10
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

常量总是静态的,但注意,不必(实际上,是不允许)在常量声明中包含修饰符static。

C#把数据类型分为两种:

  • 值类型
  • 引用类型

值类型存储在堆栈中,而引用类型存储在托管堆上。

把基本类型如int和bool,规定为值类型,而把包含许多字段的较大类型(通常在有类的情况下〉规定为引用类型,C#设计这种方式的原因是可以得到最佳性能。如果要把自己的类型定义为值类型,就应把它声明为一个结构。

值类型:
bool System.Boolean 表示true/false
char System.Char 16位的Unicode字符
sbyte System.SByte 8位有符号整形
short System.Int16 16位有符号整形
int System.Int32 32位有符号整形
long System.Int64 64位有符号整形
byte System.Byte 8位无符号整形
ushort System.UInt16 16位无符号整形
uint System.UInt32 32位无符号整形
ulong System.Uint64 64位无符号整形
float System.Single 32位单精度浮点型
double System.Double 64位双精度浮点型
decimal System.Decimal 128位高精度十进制表示法

引用类型:
object System.Object 根类型,CTS其他类型都来自它(包含值类型)
string System.String Unicode字符串

针对值类型,通过ref关键字,可以在函数参数传递时,强制使用引用。

编译选项(/target):

  • /t:exe 控制台程序
  • /t:library 有清单的类库
  • /t:module 没有清单的组建
  • /t:winexe Windows应用程序

编译后的类库,可被其他程序集引用,使用/r选项,这样就可以很简单地引用其他程序集的内容。(通过DLL引用,无需像C++ library方式声明).

XML文档
C#支持XML格式文档,但是必须///开发。
常见的xml文档注释标记有<summary><remark><param><returns><para>等。

<summary>用于描述类型或类型成员函数,在其声明之前标注。
<remarks>用于添加有关某个类型的补充信息,比如类图(怎样插入图像资源下面第四点再叙述)。<remarks>标注可以嵌入在<summary>中,也可以跟在<summary>之后。嵌入在<summary>中会在命名空间页中对类的描述表中出现(图1);与<summary>并列则会在类的描述页出现。
<para>可以嵌入于注释内,添加第二段说明:(此处嵌入于<summary>内)
<param>标签用于方法声明的注释中,描述方法的一个参数。语法为<param name=”paramname”>description</param>。
<paramref>用于代码注释中的某个单词引用某个参数,使文档以某种独特方式(通常是斜体)来设置该单词的格式。语法为<paramref name=”paramname”/>。
<returns>用于方法声明的注释,描述返回值。
<see>标签用于从文本内指定链接。语法为<see cref=”member”/>。
<seealso>标签指示文本放在“请参见”节中。语法为<seealso cref=”member”/>。cref=”member”对可以通过当前编译环境进行调用的成员或字段进行引用。编译器检查给定的代码元素是否存在,并将member传递给输出XML中的元素名。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

预处理定义

#error "this is a error"
#warning "thisi ia a warning"

#regin Step 1 section
	int a;
	string b;
#endregin

#pragma waring disable/restore 169  // 抑制或者还原指定的编译警告
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

C#中的约定是命名变量时不使用任何前缀:string Result; string Message;

部分类
partial关键字允许把类、结构、接口放在多个文件中。一般放在class/struct/interface关键字前面。

扩展方法
有许多扩展类的方式。如果有类的源代码,继承(第4章所述)就是给对象添加功能的好方法。但如果没有源代码,该怎么办?此时可以使用扩展方法,它允许改变一个类,但不需要该类的源代码。

扩展方法是静态方法,它是类的一部分,但实际上没有放在类的源代码中。

此时必须做的所有工作就是创建一个静态类,把想要增加的方法添加为一个静态方法。

using System;
using System.Runtime.CompilerServices;

namespace ConsoleHello
{
    class Program
    {

        static void Main(string[] args)
        {
            int a = 22;
            Console.WriteLine($"Hello: {a}");
            TestAgent t = new TestAgent();
            t.Print();
            t.addSomeValue(1000);
            t.Print();
        }
    }
	// 静态class和静态方法
    static class TestAgentExtension
    {
        public static void addSomeValue(this TestAgent t, int val)
        {
            t.Abc += val;
        }
    }

    class TestAgent
    {
        public int Abc { get; set; }
        public TestAgent()
        {
            Abc = 100;
            Console.WriteLine("Init abc parameter...");
        }
        public void Print()
        {
            Console.WriteLine(this.Abc);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

C#中虚函数与抽象函数

  • Virtual方法(虚方法)
    virtual 关键字用于在基类中修饰方法。virtual的使用会有两种情况:
    情况1:在基类中定义了virtual方法,但在派生类中没有重写该虚方法。那么在对派生类实例的调用中,该虚方法使用的是基类定义的方法。
    情况2:在基类中定义了virtual方法,然后在派生类中使用override重写该方法。那么在对派生类实例的调用中,该虚方法使用的是派生重写的方法。

  • Abstract方法(抽象方法)
    abstract关键字只能用在抽象类中修饰方法,并且没有具体的实现。抽象方法的实现必须在派生类中使用override关键字来实现。

密封类与方法(sealed):
对于类表示不能继承,对于方法,表示不能重写该方法。
Net基类库大量使用了密封类,使希望从这些类中派生出自己的类的第三方开发人员无法访问这些类。

泛型:

using System;
using System.Collections;
using System.Collections.Generic;

namespace ConsoleHello
{
    class Program
    {

        static void Main(string[] args)
        {
            // 强大,但是有box/unbox行为,性能损耗大
            var list = new ArrayList();
            list.Add(22);
            list.Add("zhangsan");
            list.Add(1.23);
            foreach(var i2 in list)
            {
                Console.WriteLine($"{i2.GetType()}, {i2}");
            }
            int a = (int)list[0];
            Console.WriteLine(a.GetType());

            // 可以使用泛型集合替代
            var l2 = new List<int>();
            l2.Add(11);
            l2.Add(22);
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31

泛型还可以添加约束,如:

public class MyClass<T>
	where T: IFoo, new()
{
	// ...
}
  • 1
  • 2
  • 3
  • 4
  • 5

其中where限定了类型T还必须实现了IFoo接口,new约束。
where T:stuct 对于结构约束,类型T必须是值类型
where T:class 类约束指定类型T必须是引用类型
where T:IFoo 指定类型T必须实现接口IFoo
where T:Foo 指定类型T必须派生自基类Foo
where T:new() 这是一个构造函数约束,指定类型T必须有一个默认构造函数
where T1:T2 这个约束也可以指定,类型T1派生自泛型类型T2。该约束也称为裸类型约束

委托
委托是C#实现回调函数的一种机制。

委托链:委托链是委托对象的集合。可以利用委托链调用集合中的委托所绑定的全部方法。继续在原有的基础上添加委托链的方法。

可以使用+=运算符,为委托新增方法。

同样可以使用-=运算符,为委托移除方法。

using System;

namespace ConsoleHello
{
    class Program
    {
        public delegate int MyDeleg(int a);
        static int fun1(int a)
        {
            Console.WriteLine($"fun1 {a}");
            return a + 11;
        }
        static int fun2(int a)
        {
            Console.WriteLine($"fun2 {a}");
            return a + 1100;
        }
        static void Main(string[] args)
        {
            MyDeleg t1 = fun2;
            t1 += fun1;
            // 参数相同,返回值单独返回,捕获每一个的返回值,需要使用如下方式
            var calls = t1.GetInvocationList();
            foreach(MyDeleg call in calls)
            {
                Console.WriteLine(call(3));
            }
            
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

类型

int[] a = new int[4];  
var b = new int[]{1,2,3,4};
int[] c = {1,2,3,4};
int[,] d = new int[2,3]; // 多维数组

var e = d.Clone(); // 默认引用,Clone会完成浅拷贝。

// 还支持锯齿数组,通过各自的Length来判断
int[][] a1 = new int[3][];
a1[0] = new int[2];
a1[1] = new int[5]{1,2,3,4,5};
a1[2] = new int[3];

// yield 与 foreach
using System;
using System.Collections.Generic;

namespace ConsoleHello
{
    class Program
    {
        
        static void Main(string[] args)
        {
            var list = new MyCollection();
            foreach (var v in list)
            {
                Console.WriteLine(v);
            }
        }

        public class MyCollection
        {
            public IEnumerator<int> GetEnumerator()
            {
                yield return 123;
                for(int i = 100; i < 120; i++)
                {
                    yield return i;
                }
            }
        }
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

is进行检查两个对象是否兼容
as进行显式的类型转换。失败时返回null.
sizeof确定栈中类型需要的长度。
typeof返回变量的类型,用于反射

int? a = null;
int? b = a + 10;  // null
int c = b ?? -1;   // -1 
Console.WriteLine($"{b==null} {c}");
  • 1
  • 2
  • 3
  • 4

两个变量的比较:

  • ReferenceEquals 是否引用类的同一个实例
  • Equals 可重写版,具体依赖实现的方法。
  • Equals 静态版,check null,然后比较可重写版的Equals.
  • == 运算符,可重写,严格的值比较和严格的引用比较。
Func<string, string> f1 = s => String.Format("param val: {0}", s);
f1("abc");

Func<int, int, int> f2 = (x,y) => x*y;
  • 1
  • 2
  • 3
  • 4

事件的订阅(回调函数):

using System;
using System.Threading;

namespace ConsoleHello
{
    class Program
    {
        // 事件接收者(作用机理同 回调函数)
        public static void subscribetor(int v)
        {
            Console.WriteLine($"event value: {v}");
        }
        static void Main(string[] args)
        {
            TestPublisher t = new TestPublisher();
            t.NumerChageEvent += new TestPublisher.NumberChanged(subscribetor);
            for(int i = 0; i < 10; i++)
            {
                Console.WriteLine("Add Something...");
                t.AddSome(i);
                Console.WriteLine("Sleep...\r\n");
                Thread.Sleep(1000);
            }
        }
    }

    class TestPublisher
    {
        // 代理接口定义
        public delegate void NumberChanged(int v);
        // 事件对象,可能为null
        public event NumberChanged NumerChangeEvent;

        private int _Ticks = 0;

        public void AddSome(int v)
        {
            Console.WriteLine($"Add Some {v}.");
            this._Ticks += v;
            NumerChangeEvent?.Invoke(this._Ticks);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43

字符串

System.String提供基础的功能,但是频繁构建性能低下,需要使用StringBuilder来替代,它性能更好,但是占用更多的内存。

using System;
using System.Text.RegularExpressions;

namespace ConsoleHello
{
    class Program
    {
        static void Main(string[] args)
        {
            string oldText = "hello, andy@sz, ID: 10086, my email: zhangsan@email.com, my phone: 13123456789.";
            string re_number = @"\d+";
            string re_email = @"\S+@\S+\.\S+";

            Console.WriteLine("\r\nFind text for numbers:");
            var mc = Regex.Matches(oldText, re_number);
            foreach (Group g in mc)
            {
                Console.WriteLine("{0} {1}",g.Index,g.ToString());
            }
            Console.WriteLine("\r\nFind text for email:");
            var mc2 = Regex.Matches(oldText, re_email);
            foreach (Group g in mc2)
            {
                Console.WriteLine("{0} {1}", g.Index, g.ToString());
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

集合

System.Collections 和 SYstem.Collections.Generic。

  • ArrayList 动态数组,容量自增
  • Hashtable 基于Object的hashmap
  • BitArray

泛型集合:

  • List 等效ArrayList
  • Dictionary<K,V> 等效hashmap
  • Queue
  • Stack
  • SortedList<TK,TV>
  • SortedDictionary<TK,TV>
  • LinkedList 指针链表
  • Lookup<TK,TV> 支持一个key多个值,但是使用方法不类同

Ref: Link

LINQ

语言集查询(Language Integrated Query,LINQ)集成了 C# 编程语言中的查询语法,可以用相同的语法访问不同的数据源。LINQ提供了不同数据源的抽象层,所以可以使用相同的语法。

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;

namespace ConsoleHello
{
    class Program
    {
        public static IList<Racer> racers;
        public static IList<Racer> GetChampions()
        {
            if ( racers != null )
            {
                return racers;
            }
            racers = new List<Racer>(40);
            racers.Add(new Racer("zhang", "san", "Italy", 33, 15, new int[] { 1950, 1965 }, new string[] { "A" }));
            racers.Add(new Racer("zhang", "si", "China", 20, 8, new int[] { 1951 }, new string[] { "A","B" }));
            racers.Add(new Racer("zhang", "wu", "UK", 30, 21, new int[] { 1950 }, new string[] { "A","C" }));
            racers.Add(new Racer("zhang", "liu", "USA", 15, 7, new int[] { 1950, 2000 }, new string[] { "C","D" }));
            racers.Add(new Racer("li", "san", "UK", 9, 5, new int[] { 1950, 1951 }, new string[] { "A" }));
            racers.Add(new Racer("wang", "san", "Italy", 51, 35, new int[] { 1951, 1965 }, new string[] { "A","D" }));
            racers.Add(new Racer("wang", "san2", "China", 23, 14, new int[] { 1965, 2000 }, new string[] { "B","C" }));
            racers.Add(new Racer("li", "san2", "Italy", 15, 3, new int[] { 1950 }, new string[] { "A","D","C" }));
            racers.Add(new Racer("zhao", "qian", "China", 37, 25, new int[] { 1950 }, new string[] { "B","D" }));
            return racers;
        }
        public static IList<Team> teams;
        public static IList<Team> GetTeams()
        {
            if (racers != null)
            {
                return teams;
            }
            teams = new List<Team>()
            {
                new Team("Team1", 1965),
                new Team("Team2", 2000,1951),
                new Team("Team3", 1950, 1965, 1951 ),
                new Team("Team4", 2001),
                new Team("Team5", 1950, 2002),
                new Team("Team6", 1950, 1965, 1951, 2001, 2002 ),
            };
            return teams;
        }
        static void Main(string[] args)
        {
            // LINQ 查询
            var query = from r in GetChampions() where r.Country == "China" orderby r.Wins descending select r.Cars;
            foreach(var v in query)
            {
                Console.WriteLine( string.Join("-",v));
            }

            var rs = GetChampions().Where((r, index) => r.LastName.StartsWith("s") && index % 2 != 0).Select(r=> (r.FirstName, r.LastName));
            foreach (var v in rs)
            {
                Console.WriteLine("rs {0:A}", v);
            }

            var rs2 = from r in GetChampions()
                      from c in r.Cars
                      where c == "A" || c == "B"
                      orderby r.LastName
                      select r.FirstName+"-"+r.LastName;
            foreach (var v in rs2)
            {
                Console.WriteLine("rs2 {0:A}", v);
            }

        }
        [Serializable]
        public class Racer : IComparable<Racer>, IFormattable
        {
            public string FirstName;
            public string LastName;
            public int Wins;
            public string Country;
            public int Starts;
            public string[] Cars;
            public int[] Years;

            public Racer(string firstName=null, string lastName=null, string country=null, int starts=0, int wins=0,
                IEnumerable<int> years=null, IEnumerable<string> cars = null)
            {
                this.FirstName = firstName;
                this.LastName = lastName;
                this.Country = country;
                this.Starts = starts;
                this.Wins = wins;
                this.Years = years.ToArray();
                this.Cars = cars.ToArray();
            }
            public int CompareTo(Racer other)
            {
                return this.LastName.CompareTo(other?.LastName);
            }
            public override string ToString()
            {
                return string.Format("{0} {1}", FirstName, LastName);
            }
            public string ToString(string format)
            {
                return ToString(format, null);
            }
            public string ToString(string format, IFormatProvider formatProvider)
            {
                switch (format)
                {
                    case null:
                    case "N":
                        return ToString();
                    case "F":
                        return FirstName;
                    case "L":
                        return LastName;
                    case "C":
                        return Country;
                    case "S":
                        return Starts.ToString();
                    case "W":
                        return Wins.ToString();
                    case "A":
                        return String.Format("{0} {1}, {2}; starts:{3}, wins:{4}", FirstName, LastName, Country, Starts, Wins);
                    default:
                        return ToString();
                }
            }

        }
        
        [Serializable]
        public class Team
        {
            public string Name;
            public int[] Years;
            public Team(string name, params int[] years)
            {
                this.Name = name;
                this.Years = years;
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146

基础

程序集由描述它的程序集元数据、描述导出类型和方法的类型元数据、MSIL代码和资源组成。
程序集的一个重要部分是程序集清单,它是元数据的一部分,描述了程序集和引用它所需要的所有信息,并列出了它所有的依赖关系。

附属程序集是只包含资源的程序集,它尤其适用于本地化。

程序集可以使用命令行实用工具 ildasm来 查看,这是一个 MsL反汇编程序。

在.NET之前的技术中,进程作为独立的边界来使用,每个进程都有其私有的虚拟内存;运行在一个进程中的应用程序不能写入另一个应用程序的内存,也不会因为这种方式破坏其他应用程序。
该进程用作应用程序之间的一个独立而安全的边界。在MT体 系结构中,应用程序有一个新的边界:应用程序域。

首先要知道2点:

  1. Control的Invoke和BeginInvoke与委托的Invoke和BeginInvoke是2个概念,不能混淆
  2. Control的Invoke和BeginInvoke,他们的形参是delegate,委托的方法是在Control的线程上执行(即UI线程)
  3. 委托的执行线程由后台线程池控制,自动管理。

补充一点:
相对来说,可以认为Invoke是同步的,而BeginInvoke是异步的

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Helloword
{
    class Program
    {
        static int TakeALongWork(int data, int ms)
        {
            Console.WriteLine("Begin to work...");
            Thread.Sleep(ms);
            Console.WriteLine("Work completed!");
            return data++;
        }
        public delegate int TakeALongWorkDelegate(int data, int ms);

        static void cb_complete_func(IAsyncResult ar)
        {
            var dl = ar.AsyncState as TakeALongWorkDelegate;
            Console.WriteLine("cb result: {0}", dl.EndInvoke(ar));
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Hello,world");

            // 直接调用
            TakeALongWork(1, 1000);
            Console.WriteLine("Method 1 over\r\n");

            // 委托,然后同步查询
            var dl = new TakeALongWorkDelegate(TakeALongWork);
            IAsyncResult ar = dl.BeginInvoke(2, 2000, null, null);
            while (!ar.IsCompleted)
            {
                Console.Write(".");
                Thread.Sleep(50);
            }
            Console.WriteLine("Method2, Result: {0}\r\n", dl.EndInvoke(ar));

            // 通过等待句柄查询
            IAsyncResult ar2 = dl.BeginInvoke(3, 2000, null, null);
            while (true)
            {
                Console.Write(".");
                if ( ar2.AsyncWaitHandle.WaitOne(50,false) )
                {
                    Console.WriteLine("Can get the result now.");
                    break;
                }
            }
            Console.WriteLine("Method3, Result: {0}\r\n", dl.EndInvoke(ar2));

            // 异步回调
            dl.BeginInvoke(4, 2000, cb_complete_func, dl);
            Console.WriteLine("Method4, Wait async result...\r\n");

            Console.Read();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61

Thread
只要有一个前台线程在运行,应用程序的进程就在运行。如果多个前台线程在运行,而main方法结束了,应用程序的进程就仍然是激活的,直到所有前台线程完成其任务为止。
在默认情况下,用 Thread类 创建的线程是前台线程。线程池中的线程总是后台线程。
在用mread类创建线程时,可 以设置 IsBackgromd属性,以确定该线程是前台线程还是后台线程。

using System;
using System.Threading;

namespace Helloword
{
    class Program
    {
         static void Main(string[] args)
        {
            Console.WriteLine("Hello,world");
            int a = 10;

            var t1 = new Thread(() =>
            {
                Console.WriteLine("subthread running in a thread. {0}", Thread.CurrentThread.ManagedThreadId);
                while (a > 0)
                {
                    Console.Write(".");
                    Thread.Sleep(500);
                    a--;
                }
                Console.WriteLine("thread exit!");
            });
            t1.Start();
            Console.WriteLine("main running in a thread. {0}", Thread.CurrentThread.ManagedThreadId);
            while (a > 0)
            {
                Console.WriteLine("{0}", a);
                Thread.Sleep(800);
            }

            Console.Read();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

Task

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Helloword
{
    class Program
    {
        static void TaskFunc1()
        {
            Console.WriteLine("Task func1 ID {0}, Thread: {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
        static void TaskFunc2(Task t)
        {
            Console.WriteLine("Task {0} completed.", t.Id);
            Console.WriteLine("Task func2 ID {0}, Thread: {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
        }
        static string TaskFunc3(object arg)
        {
            Console.WriteLine("Task func3 ID {0}, Thread: {1}", Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
            string val = string.Format("you input is {0}", (int)arg);
            return val;
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Hello,world");
            int nWorkers;
            int nCompletionPortThs;
            ThreadPool.GetMaxThreads(out nWorkers, out nCompletionPortThs );
            Console.WriteLine("{0} {1}\r\n", nWorkers, nCompletionPortThs);

            var t1 = Task.Factory.StartNew(TaskFunc1);
            
            var t2 = new Task(TaskFunc1);
            var t3 = t2.ContinueWith(TaskFunc2);
            t3.ContinueWith(TaskFunc2);
            t2.Start();

            var t4 = new Task<string>(TaskFunc3, 22);
            t4.Start();
            Console.WriteLine("\r\nt4 result: {0}\r\n", t4.Result);


            Console.Read();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

Parallel 在不同的线程中,使用不同的Task来执行一系列的事情:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace Helloword
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello,world");
            Parallel.For(1, 100, (i, pls) =>
            {
                Console.WriteLine("i:{0},\t task id:{1},\t thread Id:{2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
                if (i > 50)
                {
                    pls.Break();
                }
            });

            Console.Read();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

多线程同步

可以用于多个线程的同步技术:

  • lock语句
  • Interlocked类,原子操作简单对象
  • Monitor类,手动控制进出,并且有超时时间
  • SpinLock结构
  • WaitHandle类
  • Mutex类
  • Semaphore类,可以多个线程同时等待,设置次数
  • Event类
  • ReaderWriterLockSlim类

lock语句、interlocked类和Monitor类可用于进程内部的同步。
Mutex类、Semaphore类类 、Event类和 ReaderWriterLockSlim类提供了多个进程之间的线程同步。

http

using System;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace Helloword
{
    class Program
    {
        static async Task http_test()
        {
            HttpClient c2 = new HttpClient();
            try
            {
                var req = await c2.GetAsync("http://aicoder.vip/");
                var resp = await req.Content.ReadAsStringAsync();
                Console.WriteLine(resp);
            }
            catch (HttpRequestException e)
            {
                Console.WriteLine(e.Message);
            }
        }

        static void http_req()
        {
            WebRequest req = WebRequest.Create("http://aicoder.vip");
            req.Credentials = new NetworkCredential("admin", "xxxxx");
            WebResponse resp = req.GetResponse();
            Console.WriteLine(resp.Headers);
            Console.WriteLine(resp.ContentLength);
        }
        static void Main(string[] args)
        {
            Console.WriteLine("Hello,world");
            //WebClient c = new WebClient();
            //var buff = c.DownloadData("http://aicoder.vip/");
            //string s = Encoding.GetEncoding("UTF-8").GetString(buff);
            //string charset = Regex.Match(s, "charset=(\\S+)").Value;
            //Console.WriteLine(charset);
            //Console.WriteLine(s);

            //var ts = http_test();
            //ts.Wait();

            http_req();
  
            Console.ReadLine();
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

Windows服务

Windows 服务是可以在系统启动时自动打开(不需要任何人登录计算机)的程序.
Whdows服务可以在没有交互式用户登录系统的情况下运行,在后台进行某些处理。

操作Windows服务需要3种程序:

  • 服务程序 实际干活的
  • 服务控制程序 给服务程序发送控制,暂停指令的
  • 服务配置程序 安装和配置服务程序的

服务的安装需要注册表配置。

服务程序实现服务的功能。服务程序需要3部分:

  • 主函数
  • service-main函数
  • 处理程序

服务控制管理器(service contol Manager, SCM) 它可以把启动服务或停止服务的请求发送给服务.

Code OnStart,OnStop…
Add installer and config
installutil HelloService.exe

WPF

Basic Layout

<Window x:Class="WpfAppHello.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfAppHello"
        mc:Ignorable="d"
        Title="Basic Layout Test" Height="600" Width="800">
    <Grid x:Name="grid1">
        <Grid.RowDefinitions>
            <RowDefinition Height="*" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBox Name="txt_question" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" FontFamily="JetBrains Mono"
                 FontSize="24" Foreground="{x:Static SystemColors.ActiveCaptionTextBrush}" Grid.Row="0">
            <TextBox.Background>
                <LinearGradientBrush>
                    <LinearGradientBrush.GradientStops>
                        <GradientStop Offset="0.00" Color="LightSeaGreen" />
                        <GradientStop Offset="0.70" Color="Indigo" />
                        <GradientStop Offset="1.00" Color="LightGreen" />
                    </LinearGradientBrush.GradientStops>
                </LinearGradientBrush>
            </TextBox.Background>
            Test Code 
        </TextBox>
        <Button Name="btn_go" Width="100" Height="30" Margin="10,10,0,10" HorizontalAlignment="Left" Grid.Row="1"
                Click="btn_go_Click">
            Ask why?
        </Button>
        <TextBox Name="txt_answer" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"  Background="Coral" Grid.Row="2">
            Text Code
        </TextBox>
    </Grid>
</Window>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/169844
推荐阅读
相关标签
  

闽ICP备14008679号