相关文章推荐
紧张的香瓜  ·  c++ string utf16 - CSDN文库·  昨天    · 
强健的碗  ·  basic_string 类 | ...·  昨天    · 
阳刚的小狗  ·  Java8 Stream ...·  5 小时前    · 
知识渊博的斑马  ·  Excel ...·  6 月前    · 
儒雅的企鹅  ·  Limits for Microsoft ...·  1 年前    · 
体贴的拐杖  ·  ChatGPT ...·  1 年前    · 

2.Dapper使用事物时,必须先将Connection打开,否则会报错:

 using (var connection = ConnectionFactory.GetConnection())
         connection.Open();
         var trans = connection.BeginTransaction();
         connection.Execute( "insert into table1 values(@a,@b,@c)" ,obj1s, trans);
         trans.Commit();

注意一定要connection.Open();如果不使用事物的话就无所谓了

3.class 与 struct的区别:class是引用类型,struct是值类型,区别如下代码:

声明一个类:

public class PersonClass
        public string Name { get; set; }
        public int Age { get; set; }
        public override string ToString()
            return string.Format("Name:" + Name + ",Age:" + Age.ToString());

声明一个结构:

public struct PersonStruct
        public string Name { get; set; }
        public int Age { get; set; }
        public override string ToString()
            return string.Format("Name:" + Name + ",Age:" + Age.ToString());

测试代码如下:
单个对象测试:

		static void Main(string[] args)
            //pc2会随着pc1的变化而变化,他们指向的是同一个内存
            Console.WriteLine("Class Test:");
            PersonClass pc1 = new PersonClass();
            pc1.Age = 1;
            PersonClass pc2 = pc1;
            Console.WriteLine(pc2);
            pc1.Age = 2;
            Console.WriteLine(pc2);
            //ps2并不会随着ps1的变化而变化,他们指向的是两块不同的内存
            Console.WriteLine("Struct Test:");
            PersonStruct ps1 = new PersonStruct();
            ps1.Age = 1;
            PersonStruct ps2 = ps1;
            Console.WriteLine(ps2);
            ps1.Age = 2;
            Console.WriteLine(ps2);
            Console.Read();

运行结果如下:
在这里插入图片描述
数组测试:(注意有坑

        static void Main(string[] args)
            PersonStruct[] personStructs = new PersonStruct[2];
            for (int i = 0; i < personStructs.Length; i++)
                personStructs[i].Age = i;
            PersonClass[] personClasses = new PersonClass[2];
            for (int i = 0; i < personClasses.Length; i++)
                personClasses[i].Age = i;//此处会报错,因为没有实例化

运行结果如下:
在这里插入图片描述
声明了一个容量为2的数组,在没有给数组的元素赋值时,数组元素为类型的默认值
结构体是值类型,初始值为结构中各个值为初始状态的对象,而类是引用类型,初始值为null,这也就解释了上面一样的写法,为什么类会报错的原因,截图如下:

4.UDP通讯:在ReceiveFrom调用前,要调用Bind()方法或者SendTo,否则会报没有绑定本地终结点。调用SendTo方法时,如果没有调用Bind()方法,会自动分配一个本地终结点,但是主动调用Bind要给一个确定的终结点,这个终结点可能会被其他程序正在使用。如下:

这种写法会抛异常:

 var targetEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
 var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
 byte[] bytes = new byte[1024];
 EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
 int count = socket.ReceiveFrom(bytes, ref remoteEP);//会抛出没有绑定本地终结点的异常

解决的办法就是在调用ReceiveFrom之前调用一次SendTo或者Bind:

var targetEP = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.SendTo(Encoding.UTF8.GetBytes("hello,i am client"),targetEP);//会自动给socket分配一个本地终结点
byte[] bytes = new byte[1024];
EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
int count = socket.ReceiveFrom(bytes, ref remoteEP);

5.在For循环中,开启线程要采用带参数的,否则,后果如下:

在这里插入图片描述
正确的姿势为:
在这里插入图片描述

6.使用NPOI时,注意样式(CellStyle)的实例不要太多,否则容易报错。

读取内容时,要读取到最后一行,必须<= worksheet.LastRowNum:
在这里插入图片描述

7.关于C# Winform的:

设置窗体的this.ShowInTaskbar = false会触发窗体上的子控件的Load事件,如下图所示:
在这里插入图片描述
点击按钮,设置窗体的ShowTaskbar=false时,会再次触发UserControl的Load事件,
再设置ShowTaskbar=true时,会再次触发UserControl的Load事件,所以在Load里写代码要小心,并不一定Load事件只会在窗体加载时触发一次。
个人感觉是:当窗体的ShowTaskbar属性变化时,会将窗体的子控件全部Load一遍

8.操作INI时,INI的路径要使用绝对路径,不能使用相对路径,否则会写入或者读取不成功!

封装一个操作INI的方法:

public class CommonMethod
        static object lockObj = new object();
        [DllImport("kernel32")]
        private static extern long WritePrivateProfileString(string section, string key, string val, string filePath);
        [DllImport("kernel32")]
        private static extern int GetPrivateProfileString(string section, string key, string def, StringBuilder retVal, int size, string filePath);
        public static void IniWriteValue(string sectionName, string key, string value,string fileName)
            WritePrivateProfileString(sectionName, key, value, fileName);
        /// <summary>
        /// 读取INI文件的内容,内容的默认长度为1000
        /// </summary>
        /// <param name="section"></param>
        /// <param name="key"></param>
        /// <param name="fileName"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public static string IniReadValue(string section, string key, string fileName,int size=1000)
                StringBuilder stringBuilder = new StringBuilder(size);
                GetPrivateProfileString(section, key, "", stringBuilder, size, fileName);
                return stringBuilder.ToString().Trim();               
            catch (Exception e)
                throw;
string iniPath = "test.ini";
CommonMethod.IniWriteValue("Test", "Count", "3", iniPath);
Console.Read();

运行完,发现程序目录没有test.ini,也没有写入任何东西:

在这里插入图片描述
当把上面的代码改为:

string iniPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "test.ini");
CommonMethod.IniWriteValue("Test", "Count", "3", iniPath);
Console.Read();

运行,发现能写进去:

在这里插入图片描述
综上,INI操作时,INI的路径一定要用绝对路径,不要用相对路径,这和操作txt文件不一样!!

9.操作List的时候要注意以下两点:

不能在Foreach的时候移除被遍历集合的元素!!!;
最好不要在For循环的时候移除被循环集合的元素!!!;
经常看到别人写的C#代码,上来就是一个Try…Catch,然后Try里做的事情就是:

foreach(var i in list) //dosomthing.. list.Remove(i) catch()

哪些场景需要遍历集合的元素,然后移除呢?比如对设备进行发送指令,有轮询设备状态的指令,有手动复位的指令,有其他手动需要发送的指令,手动发送指令的时候,肯定这个时候不能发送轮询状态,这个时候手动发送的指令优先级最高,需要一个list来装指令,手动的指令就放在list的最前面,然后一个线程去消费这个list。当另一个线程检测到list有指令的时候就需要把指令取出来发送给设备,取出指令的过程:
遍历集合-》获取一个元素(一条指令)-》发送设备指令-》移除这个指令
这里就涉及到遍历移除操作,于是就有上面的代码。
我的解决方法是:(虽然没有更好的办法)

var list_copy=list.ToList();//复制一个list
foreach(var i in list_copy)
	//dosomthing..
	list.Remove(i);

至于为什么最好不要在For循环的时候移除被循环集合的元素,大家可以试验一下
参考这个文章的:https://blog.csdn.net/z15732621582/article/details/73896321?locationNum=10&fps=1

10.单例模式时,遍历属性调用ToString时需要注意,是否会造成无限递归。

请看如下有BUG的代码:

class Program
        static void Main(string[] args)
            Person p = Person.Instance;
            p.Name = "Tony";
            p.Age = 111;
            Console.WriteLine(p);
            Console.ReadLine();
    class Person
        private static object lockObj = new object();
        private static Person instance;
        private Person()
        public int Age { get; set; }
        public string Name { get; set; }
        public static Person Instance
                if (instance == null)
                    lock (lockObj)
                        if (instance == null)
                            instance = new Person();
                return instance;
        public override string ToString()
            StringBuilder sb = new StringBuilder();
            foreach (var prop in this.GetType().GetProperties())
                sb.AppendFormat("{0}:{1};",prop.Name,prop.GetValue(this,null));
            return sb.ToString();

运行效果如下:
在这里插入图片描述
为什么?
因为this.GetType().GetProperties()会把Instance也获取到,然后调用Instance的ToString方法,从而一直递归循环
要解决这种BUG有两种方法。
1.获取到是Instance时就不管:

public override string ToString()
    StringBuilder sb = new StringBuilder();
    foreach (var prop in this.GetType().GetProperties())
        if (prop.Name == "Instance")
            continue;//跳过Instance
        sb.AppendFormat("{0}:{1};",prop.Name,prop.GetValue(this,null));
    return sb.ToString();

方法2:我们观察到Instance是静态属性,因此我们可以跟成员属性进行区分:

public override string ToString()
    StringBuilder sb = new StringBuilder();
    foreach (var prop in this.GetType().GetProperties(System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance))
        sb.AppendFormat("{0}:{1};",prop.Name,prop.GetValue(this,null));
    return sb.ToString();

11 WPF使用MVVM模式,给界面的RatioButton赋值问题

如下:WPF界面
在这里插入图片描述
三个RatioButton在一个Groupbox中,它们是互斥的关系:

<GroupBox Grid.Column="0" Header="确认状态">
                <StackPanel>
                    <RadioButton  Content="已确认"  Margin="0,5,0,0"
                             IsChecked="{Binding IsAck,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" >
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Checked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </RadioButton>
                    <RadioButton Content="未确认" Margin="0,5,0,0" IsChecked="{Binding IsUnack, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Checked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </RadioButton>
                    <RadioButton  Content="全部" Margin="0,5,0,0" IsChecked="{Binding IsAckAndUnack,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
                        <i:Interaction.Triggers>
                            <i:EventTrigger EventName="Checked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding AckCheckedChangedCmd}" />
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                    </RadioButton>
                </StackPanel>
            </GroupBox>

现在我们想让程序启动时,自动选中第2个RatioButton,也就是这三个变量的值是互斥的,同一时刻只能有一个为true,我只想赋值一个变量就想达到这个效果:

IsUnack=true;

如果把这一句加入到ViewModel的构造函数中,则不一定会起作用,因为其他两个变量IsAck和IsAckAndUnack的初始值也为true,当ViewModel赋值到View的DataContext上时,由于界面互斥的关系,IsUnack/IsAck会被自动赋值为false,IsAckAndUnack保持为true,因为IsAckAndUnack绑定的控件在最后面,为了解决这个问题,我们只有在窗体加载完成后再赋值IsUnack=true.由于我们使用的是MVVM模式,我们将窗体的加载函数绑定到命令,在命令的处理函数中执行IsUnack=true:
MainWindow.xaml:

 <i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction Command="{Binding WindowLoadCmd}"></i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>

MainWindowViewModel:

 private bool isAck=true;
 public bool IsAck
     get { return isAck; }
     set { isAck = value;RaisePropertyChanged(nameof(IsAck)); }
 private bool isUnack=true;
 public bool IsUnack
     get { return isUnack; }
     set { isUnack = value;RaisePropertyChanged(nameof(IsUnack)); }
 private bool isAckAndUnack = true;
 public bool IsAckAndUnack
     get { return isAckAndUnack; }
     set { isAckAndUnack = value;RaisePropertyChanged(nameof(IsAckAndUnack)); }
 public DelegateCommand WindowLoadCmd { get; set; }
 public MainWindowViewModel()
      WindowLoadCmd = new DelegateCommand(WindowLoad);
 private void WindowLoad()
     IsUnack=true;

12.WCF死锁的问题

具体现象见:https://social.microsoft.com/Forums/he-IL/1933a906-b5b1-4f40-a56b-67b7f6de4ca3/2085120110wcf22238358433622926102303403838239064?forum=visualcshartzhchs
当在客户端调用服务端的方法里,去使用回调时,客户端会卡住的问题,解决办法,在客户端实现的回调类上加这个标注:

[CallbackBehavior(UseSynchronizationContext = false)]

13.WPF 报 “无法使用 DependencyObject,它属于其父 Freezable 之外的其他线程”的错误

在这里插入图片描述
出现这样错误的原因是SolidColorBrush不能在主线程之外的线程创建
参考文章:http://www.111com.net/net/173/117010.htm

14 在现场中调用App.Current.MainWindow报错:

报错的写法:

 Task.Factory.StartNew(() =>
     **var main1 = App.Current.MainWindow;**
     var result= PendingBox.Show("this is pendingbox in thread", "提示",false, main1 );
     for (int i = 0; i < 10; i++)
         this.Dispatcher.Invoke(()=> result.UpdateMessage(i.ToString()));
         Thread.Sleep(1000);
     result.Close();
 });

正确的写法:

var main = App.Current.MainWindow;
Task.Factory.StartNew(() =>
    var result= PendingBox.Show("this is pendingbox in thread", "提示",false, main );
    for (int i = 0; i < 10; i++)
        this.Dispatcher.Invoke(()=> result.UpdateMessage(i.ToString()));
        Thread.Sleep(1000);
    result.Close();
});

15 .netcore web api报414 url太长的解决方案

使用.netcore编写的WebApi进行get查询操作时,报如下错误:

请添加图片描述
解决方法:
设置kestrel服务器的缓冲大小:

public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                    webBuilder.UseStartup<Startup>();
                    webBuilder.UseUrls("http://*:10000");
                    webBuilder.UseKestrel(a =>
                        a.Limits.MaxRequestLineSize = 32 * 1024 * 10;
                        a.Limits.MaxRequestHeadersTotalSize = 32 * 1024 * 10;
                    });
                .UseNLog();

MaxRequestLineSize MaxRequestHeadersTotalSize 设置为320KB,默认为32KB

Timespan需要注意的事情

请看如下代码:

static void Main(string[] args)
     var ts=TimeSpan.FromHours(5000.123);
     Console.WriteLine(ts.Hours);
     Console.ReadKey();

输出的结果竟然是8!!!!
在这里插入图片描述
看看注释定义,小时数的定义竟然是-24~23,小时不能超过24么??
在这里插入图片描述

本来想把5000.123小时换算成时分秒的,怎么办?正确的方式如下:

 var ts=TimeSpan.FromHours(5000.123);
 Console.WriteLine($"{((int)(ts.TotalHours)).ToString("00")}:{ts.Minutes.ToString("00")}:{ts.Seconds.ToString("00")}");
 Console.ReadKey();

ToString("00")仅仅是想把事件转成最少两位显示而已
在这里插入图片描述

20230512遇到的坑

这个坑让我排查一个堆栈溢出的问题排查了将近一下午的时间!!!
请看如下代码示例:

static void Main(string[] args)
    var flag = false;
    Func<bool> f1 = () => flag == true;
    Func<bool> f2 = () => flag = true;
    var a = 5;
    Func<int> f3 = () => a;
    Func<int> f4 = () => a=6;
    Test(f1);
    Test(f2);
    Test(f1);
    Console.WriteLine("=====");
    Test(f3);
    Test(f4);
    Test(f3);
    Console.ReadLine();
static void Test<T>(Func<T> f)
    Console.WriteLine(f());

Func<bool> f2 = () => flag = true;这一句,大家肯定想的是无法通过编译,貌似flag=true不返回信息。但是它能通过编译!!!
仔细想想,有的老一辈程序员喜欢这样写代码:

a=b=c=d=100;

这样写的意思就是把变量a/b/c/d都赋值为100
那其实a=6就返回a的值(赋值之后的值返回),这是一个语法糖
那么这个坑是如何造成我排查一下午的堆栈溢出的呢?
贴出我的代码:使用wpf+prism写的遇到的坑:

public class MainWindowViewModel:BindableBase
	public MainWindowViewModel()
		this.PushCmd = new DelegateCommand(Push, () => this.IsError=false);
	public DelegateCommand PushCmd { get; set; }
	private bool isError;
    public bool IsError
        get { return isError; }
            isError = value;
            this.RaisePropertyChanged(nameof(IsError));
            this.PushCmd?.RaiseCanExecuteChanged();

本来是:this.PushCmd = new DelegateCommand(Push, () => this.IsError==false);错写为:this.PushCmd = new DelegateCommand(Push, () => this.IsError=false);还能通过编译。这样就导致:

  • wpf界面获取PushCmd是否能执行
  • 执行() => this.IsError=false委托
  • 委托中对IsError赋值false
  • IsError的set中刷新PushCmd是否能执行
  • 执行() => this.IsError=false委托

  • 发现程序一直执行() => this.IsError=false从而进入递归死循环导致堆栈溢出
namespace InstrumentUtilityDotNet public class NotifyObjectChanged : INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged; public static string str_systemconfig_FileName = “config.ini”; string str = GlobalVar.str_systemconfig_AllPath + GlobalVar.str_systemconfig_FileName; INIFile myIniFile = new INIFile(str); int temp_key = 0; int temp_s 包括ASP.NET和ASP.NET AJAX + JSON两个DEMO,最低耗时35ms左右(AJAX+JSON)。百万级数据库查询分页,使用Oracle 存储过程。Asp.net 2.0 + ,Oracle 10g + 开发环境:ASP.Net 2.0 - 4.5, Oracle 11g r2项目开源发布,供下载学习。需要自己建一个TEST数据表,包括3个字段ID,COL1,COL2。Descr 在Form Shown中showInTaskBar =false 或者 this.Hide(); 转载于:https://www.cnblogs.com/runliuv/p/3657542.html... 这是一个普遍的问题:如果我们再程序中使用了多线程技术,而工作线程(后台线程)如果需要更新界面上的元素(例如进度条等),就会有一个线程安全性问题,因为进度条是由主线程创建出来的。 关于这一点,大致上看,WPF的机制与Windows Forms是没有差别的。我们在Windows Forms中需要按照下面的方式更新窗体元素。 using System; using System.Windows.Forms; using System.Threading; namespace WindowsFormsA 场景:在一些后台管理系统中编辑或新增业务数据的时候都需要记录用户的操作日志,但是如果每次都单独这块操作日志,又显得非常繁琐,所以这边使用泛型、反射以及一定的实体约束来进行了通用操作日志封装。废话不多讲,直接上代码—— 封装端代码: using Model.Entity; using Model.Request; using System; using System.Linq; using ... BaseResponse response = new BaseResponse();            PropertyInfo[] properties = request.GetType().GetProperties();            foreach (var item in properties)            {                if (item.G...