1、Fun委托的使用:
当我们的方法参数,是需要一个实时变化的值,参数应该用委托来做,比如如果用值类型的话,那么C#默认只会识别传进来的时候值类型的数值,外面即使变化了,此方法的值类型还不会变,所以应该使用委托来做参数。
Process_PalletBase(Func<bool> TrayFull)
{
if (_TrayFull.Invoke())//判断委托的值
{
_PalletAction = PalletActionType.PutAndTakePallet;
_TrayFull=()=> false;//给委托赋值
GeneralParamHelper.Cur.LoadTrayFull = false;
Ref_Step($"开始{stationName}流程");
}
}
2、遇到一个现象:所有电机轴的父类,并没有单例模式,但是具体电机对象是具有单例模式的。
当我们要写一个公共的方法,参数是为电机父类,使用此方法时,传进来不同的电机对象实例,那么调用的时候,会先执行电机对象的静态单例字段,再执行:base()方法,(执行父类构造之前,会先按照顺序将父类的字段属性先执行,再执行父类的构造函数),然后再执行子类的构造方法,然后再执行子类调用的父类方法。所以这样使用是没有问题的,虽然子类是单例,但是传参数的时候,会将子类的单例一并实现。
3、关于break,continue,return的使用:
static void Main(string[] args)
{
int a = 0;
WorkMode workMode = new WorkMode();
workMode = WorkMode.SpotInspection;
while (true)
{
switch (workMode)
{
case WorkMode.TestRun:
continue;//后面的代码不再执行,但是不会跳出while循环
case WorkMode.AutoLine:
break;//只跳出switch循环,后面的打印代码会继续执行
case WorkMode.SpotInspection:
return;//后面的代码不再执行,直接到方法最后的括号
}
Console.ReadLine();
}
Console.ReadLine();
}
4、获取基目录,它由程序集冲突解决程序用来探测程序集
AppDomain.CurrentDomain.BaseDirectory
5、
给界面加载图片:
- 在文件中,Debug和release下面都添加图片
this.Frm.Panel2.BackGroundImage=Image.FormFile("mainbg.png");//图片名称添加
this.Frm.Panel2.BackgroundImageLayout=ImageLayout.Stretch;//将图片伸展
6、 当前窗体关掉的写法:
this.close();
7、改善用户使用体感:当输完一行文本时,用户按下enter键,鼠标自动跳至下一行需要输入的文本框,实现:文本框的keyDown事件
if(this.txt.Trim().Length!=0 && e.key.value==13)//click事件参数e
{
this.txt1.Focus();
this.txt1.SelectAll();
}
8、
单例模式中:
外部调用永远只有一个对象,这就导致一旦外面改变此对象的任意属性,那其它引用的地方也会跟着改变。如果不是单例模式,那就会有多个对象,多个存储空间
9、
继承:
子类继承父类的公开属性,当没有赋值的时候,调用的就是父类的属性内容,如果子类改变该属性的值,变化的仅为该子类,父类与其它的子类是不会变化的,这就解释了MotionRun中的step,是不会被其他子流程改变的。
10、
如果我们想持续追踪某个变量,在特定时间内不断判断,那么我们不可以直接传变量本身,因为这样传递的是值,相当于复制的一个对象在用
可以使用委托来做Func (无参,有返回值)
传递的时候使用:()=>Bool 量即可
使用的时候方法参数:
public void Check(Func<bool> bool)
{
}
//使用的时候:
Check(()=>bool)
11、
C# Parallel:
与Task有些相似,并行执行一系列任务,然后等待所有完成,和Task比起来,省略了Task.WaitAll这一步,也缺少Task的相关管理功能。
常用的两种形式:
Parallel.Invoke(Params Action[] actions)
用并行,普通的Exception并不能获取到异常,为并行诞生的AggregateExcepation可以获取到一组异常,我们需要遍历异常数组
数据的并行:
Parallel.For方法:用于处理针对数组元素的并行操作
Parallel.Foreach方法:用于处理泛型集合元素的并行操作
12、
PC多核处理器:
处理器里面有多个进程,进程里处理多个线程,单核处理器也有进程,进程里也有多个线程,区别在于处理速度上
13、
怎样使事件只允许一个方法注册:
可以像属性一样的去使用,get,set
- 声明一个委托当做私有字段(相当于属性的私有字段)
- 声明一个事件,拥有add与remove方法
- 有一个公开方法,在本类的内部的方法中调用事件,外部通过公开方法调用事件
14、 C#不支持多重继承,因为结构已经隐式地继承自ValueType,所以结构不支持继承。
15、数据实现实时线性转换:(其实就是解析的时候我们赋值的是字段,使用的时候我们用的是属性,属性只有get方法,这样就不会数据被改变,而且在get方法中可以进行相应的计算)
//加速度
public short IAccelerateSpeedX { get; set; }
/// <summary>
/// 偏移及比例系数
/// </summary>
private const float AccelerateSpeedScale = 16.0f/ 32738.0f;
/// <summary>
/// 实际值
/// </summary>
public float AccelerateSpeedX
{
get
{
return IAccelerateSpeedX * AccelerateSpeedScale + AccelerateSpeedOffset;
}
}
//这里是收到的数据,解析后直接存到变量里面
//在这里才开始做真正的解析
//解析加速度
objJY61Param.IAccelerateSpeedX = BitConverter.ToInt16(msg, 2);
//显示使用的值
this.lbl_AccelerateSpeedX.Text = objJY61Param.AccelerateSpeedX.ToString("f2") + " " + AccelerateSpeedUnit;
16、
WPF中的Settings设置,一个Setting有4个属性Name,Type,Scope,Value。重点讲一下Scope属性,Scope属性有两个值Application,User。这两者区别,Scope值为Application时,对应的Setting在运行时不可以修改。Scope值为User时,对应的Setting在运行时可以修改。
Setting保存位置:当程序编译后,Setting的值保存在文件夹Properties文件中,APP.config中也有保存。
17、double数值会有正无穷负无穷,返回的数值就为N/A ,是也有方法(IsNaN)是可以排除N/A的,立景项目基恩士测高仪,在使用的时候就总会测出无穷大,得到N/A,为了获取数值,只能将N/A数值都刷选出来。
18、立景项目,和欧姆龙PLC通讯时,最后调用FinsTCPHelper需要为同一个对象,所以FinsTCPHelper该类还是写成的单例模式,如下代码:
private static FinsTCPHelper tCPHelper ;
private FinsTCPHelper()
{
}
readonly object ob_lock = new object();
public static FinsTCPHelper CreateFinsTCP(string _ParamPath = null)
{
if(tCPHelper==null)
{
lock(OB_LOCK)
{
if(tCPHelper==null)
{
if (_ParamPath == null)
{
IP = IPAddress.Parse(Properties.Settings.Default.IP);
Port = Properties.Settings.Default.Port.ToString();
SA = 100;
}
else
{
ParamPath = _ParamPath;
//判断路径是否存在
if (File.Exists(_ParamPath))
{
//就读取
string strIp = IniAPI.INIGetStringValue(_ParamPath, "ParamServer", "IP", "127.0.0.1");
IP = IPAddress.Parse(strIp);
string strPort = IniAPI.INIGetStringValue(_ParamPath, "ParamServer", "Port", "8100");
Port = strPort;
string strPort1 = IniAPI.INIGetStringValue(_ParamPath, "ParamServer", "SA", "100");
SA = int.Parse(strPort1);
}
else
{
IP = IPAddress.Parse(Properties.Settings.Default.IP);
Port = Properties.Settings.Default.Port.ToString();
SA = 100;
IniAPI.INIWriteValue(_ParamPath, "ParamServer", "IP", IP.ToString());
IniAPI.INIWriteValue(_ParamPath, "ParamServer", "Port", Port.ToString());
IniAPI.INIWriteValue(_ParamPath, "ParamServer", "SA", SA.ToString());
}
}
tCPHelper = new FinsTCPHelper();
}
}
}
return tCPHelper;
}
但是这个通讯时基于socket通讯,当我们关闭之后,这个client对象被注销了,重新连接的时候,必须要有一个新的客户端对象,所以我们在连接的地方new一个新的客户端对象,如下代码:
public bool Open()
{
lock (ob_lock)
{
try
{
if (!IsConnected)
{
if (finsTCP == null)
{
//连接的时候每次都创建一个新的对象
finsTCP = new OmronFinsTCP.Net.EtherNetPLC();
}
string strIp = IP.ToString();
if ((strIp != "" || strIp != null) && strIp.Length >= 11)
{
string[] result = strIp.Split('.');
//finsTCP.DA1 = byte.Parse(result[3]);
}
//finsTCP.SA1 = pcadress;
short re = finsTCP.Link(IP.ToString(), short.Parse(Port), 3000);
if (re == 0)
{
IsConnected = true;
}
else
{
IsConnected = false;
}
}
}
catch (Exception ex)
{
IsConnected = false;
throw new Exception(ex.Message);
}
if (IsConnected)
{
IniAPI.INIWriteValue(ParamPath, "ParamServer", "IP", IP.ToString());
IniAPI.INIWriteValue(ParamPath, "ParamServer", "Port", Port.ToString());
}
}
return IsConnected;
}
关闭的时候就将该对象赋值为null
public bool Close()
{
lock(ob_lock)
{
IsConnected = false;
short re = finsTCP.Close();
finsTCP = null;
if (re != 0)
{
return false;
}
else
{
IsConnected = false;
return true;
}
}
}