2017.07.24-2017.07.30
关于组件(Component)、控件(Control)和用户控件(UserControl)
在.NET中有组件、控件和用户控件。其实从字面上已经可以理解各自的不同了。但是具体关系其实是从类的继承上来区别的。一般控件派生于:Control类,所以从此类派生出的称之为控件。一般组件派生于:Component类,所以从此类派生出的称之为组件。一般用户控件派生于:UserControl类,所以从该类派生出的称之为用户控件。(我们之所以这么叫其实是因为英文翻译上的习惯)他们之间的关系主要是:UserControl继承Control继承Component。
但是具体在用时有什么区别呢?这主要是从设计的角度去考虑的。
组件和一般类的区别:我们总是习惯于面向对象的设计方式。而对象则是由类实例化而来。我们强调万事万物皆对象,把对象看作设计的基本单元。
所谓组件其实是面向组件的设计方式,我们把组件作为设计的基本单元。组件即为程序的组成部分。其实是构成程序的一个最基本的单元。一个组件其实可以包括多个类。这与传统的面向对象的设计方式有点区别。算是更高一层的封装。
而控件和用户控件其实是组件按照具体的用途的一种划分,它们都是组件。控件的突出特点就是交互式组件。而用户控件则是将某些特定的组件或控件复合从而实现特定的业务功能。所以用户控件往往是从业务角度来设计的。
其实,程序设计现在已经不在是简单的面向对象。
从以往的面向过程到
面向对象
面向组件
面向服务
面向方向
其实有很多。
菜单的动态生成及事件绑定(会用到类型强转)
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace MenuDynamic
{
public partial class Form1 : Form
{
ToolStripMenuItem[] toolStripMenuItem = new ToolStripMenuItem[5];
public Form1()
{
InitializeComponent();
for (int i = 0; i < toolStripMenuItem.Length; i++)
{
toolStripMenuItem[i] = new ToolStripMenuItem();
toolStripMenuItem[i].Name = "Series" + i;
toolStripMenuItem[i].Tag = "Series";
toolStripMenuItem[i].Checked = true;
contextMenuStrip1.Items.Add(toolStripMenuItem[i].Name);
toolStripMenuItem[i].Text = toolStripMenuItem[i].Name;
//contextMenuStrip1.Items[toolStripMenuItem[i].Name].Checked = true;
//绑定事件,两次
contextMenuStrip1.Items[toolStripMenuItem.Length - 2 + i].Click += toolStripMenuItem_Click;
//toolStripMenuItem4.Click += toolStripMenuItem_Click;
}
//toolStripMenuItem2.Checked = true;
//下面这句话是不起作用的,需要用类型强转获取当前选中的item,强转中,有时会发生自己转成自己的情况
toolStripMenuItem[1].Checked = true;
//这里能用foreach是因为不会在其中发生remove和add,如果有,就会报错,出现异常
foreach (var item in contextMenuStrip1.Items)
{
if (item is ToolStripMenuItem)
{
ToolStripMenuItem menuItem = item as ToolStripMenuItem;
menuItem.Checked = true;
}
}
}
//toolStripMenuItem的点击事件,check属性要在这里设置,注意类型强转
private void toolStripMenuItem_Click(object sender, EventArgs e)
{
((ToolStripMenuItem) sender).Checked = !((ToolStripMenuItem) sender).Checked;
label1.Text = sender.ToString();
}
}
}
数组和集合的对比
集合提供了程序中管理数据的各种办法,它们能够取代数组灵活地管理对象组。
数组和集合之间的差别在于:
- 数组声明了元素类型,集合却没有。这是因为集合类将元素存储为对象
- 数组实例的大小是固定的,而集合类可以按照需要动态调整自身大小
- 数组是可读写的数据结构,无法创建一个只读数组。但是通过使用只读ReadOnly方法,就可以以只读方式使用集合类。当以只读方式使用集合类时,任何试图写入的操作都将引起运行时异常。
封装
是一种信息隐蔽技术,用户只能看到对象封装界面上的信息,对象内部对用户是隐藏的。目的在于把设计者和使用者分开。
Dictionary类
在C#中,Dictionary提供快速的基于键值的元素查找。当你有很多元素的时候可以使用它。它包含在System.Collections.Generic名空间中。在使用前必须声明它的键类型和值类型。
using System;
using System.Collections.Generic;
public class Example
{
public static void Main()
{
// Create a new dictionary of strings, with string keys.
//第一个string是Key,第二个String是Value
Dictionary<string, string> openWith =
new Dictionary<string, string>();
// Add some elements to the dictionary. There are no
// duplicate keys, but some of the values are duplicates.
//往dictionary中添加元素,Key不能包含重复值,Value可以包含重复值
//比如可以把对象作为值,对象中某个不可重复的元素作为键,即可做到快速的增删改查操作
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
openWith.Add("dib", "paint.exe");
openWith.Add("rtf", "wordpad.exe");
// The Add method throws an exception if the new key is
// already in the dictionary.
//若字典中已经包含某个key了,则Add方法会抛出异常
try
{
openWith.Add("txt", "winword.exe");
}
catch (ArgumentException)
{
Console.WriteLine("An element with Key = \"txt\" already exists.");
}
//可通过键来找到对应的值
// The Item property is another name for the indexer, so you
// can omit its name when accessing elements.
Console.WriteLine("For key = \"rtf\", value = {0}.",
openWith["rtf"]);
// The indexer can be used to change the value associated
// with a key.
//改
openWith["rtf"] = "winword.exe";
Console.WriteLine("For key = \"rtf\", value = {0}.",
openWith["rtf"]);
// If a key does not exist, setting the indexer for that key
// adds a new key/value pair.
openWith["doc"] = "winword.exe";
// The indexer throws an exception if the requested key is
// not in the dictionary.
//若不在字典中则会抛异常
try
{
Console.WriteLine("For key = \"tif\", value = {0}.",
openWith["tif"]);
}
catch (KeyNotFoundException)
{
Console.WriteLine("Key = \"tif\" is not found.");
}
// When a program often has to try keys that turn out not to
// be in the dictionary, TryGetValue can be a more efficient
// way to retrieve values.
//可以用此函数实现获取字典中某个键的值
string value = "";
if (openWith.TryGetValue("tif", out value))
{
Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
Console.WriteLine("Key = \"tif\" is not found.");
}
// ContainsKey can be used to test keys before inserting
// them.
//ContainsKey可以在插入元素之前检测
if (!openWith.ContainsKey("ht"))
{
openWith.Add("ht", "hypertrm.exe");
Console.WriteLine("Value added for key = \"ht\": {0}",
openWith["ht"]);
}
// When you use foreach to enumerate dictionary elements,
// the elements are retrieved as KeyValuePair objects.
//遍历
Console.WriteLine();
foreach( KeyValuePair<string, string> kvp in openWith )
{
Console.WriteLine("Key = {0}, Value = {1}",
kvp.Key, kvp.Value);
}
// To get the values alone, use the Values property.
Dictionary<string, string>.ValueCollection valueColl =
openWith.Values;
// The elements of the ValueCollection are strongly typed
// with the type that was specified for dictionary values.
Console.WriteLine();
foreach( string s in valueColl )
{
Console.WriteLine("Value = {0}", s);
}
// To get the keys alone, use the Keys property.
Dictionary<string, string>.KeyCollection keyColl =
openWith.Keys;
// The elements of the KeyCollection are strongly typed
// with the type that was specified for dictionary keys.
Console.WriteLine();
foreach( string s in keyColl )
{
Console.WriteLine("Key = {0}", s);
}
// Use the Remove method to remove a key/value pair.
Console.WriteLine("\nRemove(\"doc\")");
openWith.Remove("doc");
if (!openWith.ContainsKey("doc"))
{
Console.WriteLine("Key \"doc\" is not found.");
}
}
}
/* This code example produces the following output:
An element with Key = "txt" already exists.
For key = "rtf", value = wordpad.exe.
For key = "rtf", value = winword.exe.
Key = "tif" is not found.
Key = "tif" is not found.
Value added for key = "ht": hypertrm.exe
Key = txt, Value = notepad.exe
Key = bmp, Value = paint.exe
Key = dib, Value = paint.exe
Key = rtf, Value = winword.exe
Key = doc, Value = winword.exe
Key = ht, Value = hypertrm.exe
Value = notepad.exe
Value = paint.exe
Value = paint.exe
Value = winword.exe
Value = winword.exe
Value = hypertrm.exe
Key = txt
Key = bmp
Key = dib
Key = rtf
Key = doc
Key = ht
Remove("doc")
Key "doc" is not found.
*/
//降序字典排序
//Dictionary<string, StudentInformationClass>为字典的键值对
public static Dictionary<string, StudentInformationClass> SortDictionary_Desc(Dictionary<string, StudentInformationClass> dic)
{
List<KeyValuePair<string, StudentInformationClass>> myList = new List<KeyValuePair<string, StudentInformationClass>>(dic);
myList.Sort(delegate (KeyValuePair<string, StudentInformationClass> s1, KeyValuePair<string, StudentInformationClass> s2)
{
return s2.Value.GradeStudent.CompareTo(s1.Value.GradeStudent);
});
dic.Clear();
foreach (KeyValuePair<string, StudentInformationClass> pair in myList)
{
dic.Add(pair.Key, pair.Value);
}
return dic;
}
//升序字典排序
//Dictionary<string, StudentInformationClass>为字典的键值对
public static Dictionary<string, StudentInformationClass> SortDictionary_Asc(Dictionary<string, StudentInformationClass> dic)
{
List<KeyValuePair<string, StudentInformationClass>> myList = new List<KeyValuePair<string, StudentInformationClass>>(dic);
myList.Sort(delegate (KeyValuePair<string, StudentInformationClass> s1, KeyValuePair<string, StudentInformationClass> s2)
{
return s1.Value.GradeStudent.CompareTo(s2.Value.GradeStudent);
});
dic.Clear();
foreach (KeyValuePair<string, StudentInformationClass> pair in myList)
{
dic.Add(pair.Key, pair.Value);
}
return dic;
}
CsvHelper组件使用中遇到的问题
【中文乱码】——StreamReader sr = new StreamReader(fileStream, Encoding.GetEncoding("GB2312"));
StreamReader
类用于读取文件,可以处理任何流信息,它以一种特定的编码从字节流中读取字符。
using关键字有两个主要用途
using
关键字有两个主要用途:
- 作为指令:用于为命名空间创建别名或导入在其他命名空间中定义的类型。
- 作为语句:用于定义一个范围,在此范围的末尾将释放对象。
非托管资源和托管资源
托管资源指的是.NET
可以自动进行回收的资源,主要是指托管堆上分配的内存资源。托管资源的回收工作是不需要人工干预的,有.NET
运行库在合适调用垃圾回收器进行回收。
非托管资源指的是.NET
不知道如何回收的资源,最常见的一类非托管资源是包装操作系统资源的对象,例如文件,窗口,网络连接,数据库连接,画刷,图标等。这类资源,垃圾回收器在清理的时候会调用Object.Finalize()
方法。默认情况下,方法是空的,对于非托管对象,需要在此方法中编写回收非托管资源的代码,以便垃圾回收器正确回收资源。
委托再探
Control.Invoke
方法 (Delegate
)
在拥有此控件的基础窗口句柄的线程上执行指定的委托。即调用此方法可以将权限转交给拥有此控件的基础窗口句柄的线程。(比如,可以是反交给主线程,让主线程帮忙做)
类和线程无关。
另一种实现委托的方法,将当前窗体作为对象传给线程。这个实例中会产生包括主线程在内的三个线程。
//MyFormControl.cs
using System;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
namespace DelegateApp
{
public partial class MyFormControl : Form
{
public delegate void AddListItem();
public AddListItem myDelegate;
private Button myButton;
private Thread myThread;
private ListBox myListBox;
public MyFormControl()
{
//窗体初始化
myButton = new Button();
myListBox = new ListBox();
myButton.Location = new Point(72, 160);
myButton.Size = new Size(152, 32);
myButton.TabIndex = 1;
myButton.Text = "Add items in list box";
myButton.Click += new EventHandler(Button_Click);
myListBox.Location = new Point(48, 32);
myListBox.Name = "myListBox";
myListBox.Size = new Size(200, 95);
myListBox.TabIndex = 2;
ClientSize = new Size(292, 273);
Controls.AddRange(new Control[] { myListBox, myButton });
Text = " 'Control_Invoke' example";
myDelegate = new AddListItem(AddListItemMethod);
}
static void Main()
{
//新线程展示窗体
MyFormControl myForm = new MyFormControl();
myForm.ShowDialog();
}
//委托函数
public void AddListItemMethod()
{
String myItem;
for(int i=1;i<11;i++)
{
myItem = "MyListItem" + i.ToString();
myListBox.Items.Add(myItem);
myListBox.Update();
Thread.Sleep(300);
}
}
private void Button_Click(object sender, EventArgs e)
{
//再起一个线程
myThread = new Thread(new ThreadStart(ThreadFunction));
myThread.Start();
}
private void ThreadFunction()
{
//把当前窗体作为对象传进去,生成MyThreadClass的对象
MyThreadClass myThreadClassObject = new MyThreadClass(this);
//利用函数调用委托
myThreadClassObject.Run();
}
}
}
//MyThreadClass.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WindowsFormsApp4
{
public class MyThreadClass
{
MyFormControl myFormControl1;
public MyThreadClass(MyFormControl myForm)
{
myFormControl1 = myForm;
}
public void Run()
{
// Execute the specified delegate on the thread that owns
// 'myFormControl1' control's underlying window handle.
//将权限转交给拥有此控件的基础窗口句柄的线程,执行委托
myFormControl1.Invoke(myFormControl1.myDelegate);
}
}
}
接口
- 接口即规范。接口中所声明的成员都是公共的;
- 接口不能包含有具体实现代码的成员,也不能包含构造函数;
定义接口
在默认情况下,接口和类一样,将声明为内部访问(internal),即只能在同一程序集中访问,因此如果要让接口对外公开,应当加上public
修饰符。
接口与多继承
在C++语言中允许多继承,但是C#不行。C#一个类可以实现多个接口,在形式上达到了多继承的效果。
实现接口
=============================================================================
拷贝构造函数
与有些语言不同,C# 不提供复制构造函数。如果创建了新的对象并希望从现有对象复制值,必须自行编写适当的方法。(MSDN文档)
用途
构造函数是用来初始化我们要创建实例的特殊的方法。通常我们要将一个实例赋值给另外一个变量c#只是将引用赋值给了新的变量实质上是对同一个变量的引用,如果想在赋值的同时创建一个全新的变量而不只是对实例引用的赋值,我们可以使用复制构造函数。
数组
一维数组
int[] nums = new int [3];
二维数组
声明
int[,] arr;
ys为二维数组
int row = ys.GetLength(0);//获取行数
int col = ys.GetLength(1);//获取列数
取二维数组的某一行:
//ys为二维数组
for (int i = 0; i < row; i++)
{
//获取一行数据到tmp中
for (int j = 0; j < col; j++)
{
tmp[j] = ys[i, j];
}
}
switch条件语句
switch语句是分支选择语句,switch中的表达式是一个整型或字符串型表达式,case的内容根据switch而定
//比如
Console.write("请输入国家名称:");
string country = Console.ReadLine();
string language;
switch(country)
{
case "America":
case "Britain":
language = "English";
break;
default :
language = "unknown"
break;
}
Console.WriteLine(language);
===================================
Matlab的MAT格式
文件中开头一部分是:MATLAB 5.0 MAT-file, Platform: PCWIN64, Created on: Tue Jul 25 14:37:21 2017
类似的字样。