<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
xmlns:content="http://purl.org/rss/1.0/modules/content/"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:wfw="http://wellformedweb.org/CommentAPI/">
<channel>
<title>小夏的猪窝 - CSharp</title>
<link>https://blog.x-tools.top/category/CSharp/</link>
<atom:link href="https://blog.x-tools.top/feed/category/CSharp/" rel="self" type="application/rss+xml" />
<language>zh-CN</language>
<description></description>
<lastBuildDate>Sun, 12 Jan 2025 09:27:00 +0000</lastBuildDate>
<pubDate>Sun, 12 Jan 2025 09:27:00 +0000</pubDate>
<item>
<title>Auto_Si9000 阻抗计算神器，让 PCB 设计效率飙升！</title>
<link>https://blog.x-tools.top/archives/103/</link>
<guid>https://blog.x-tools.top/archives/103/</guid>
<pubDate>Sun, 12 Jan 2025 09:27:00 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[前言该项目的上篇文章是：关于SI9000计算阻抗接口的研究；上篇讲解了Si9000的接口调用，可以被任何高级编程语言使用，如上篇文章中的Python；本篇发布前，本人也使用Python写了6个常...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h2>前言</h2><p>该项目的上篇文章是：<a href="https://blog.x-tools.top/archives/98/">关于SI9000计算阻抗接口的研究</a>；<br>上篇讲解了Si9000的接口调用，可以被任何高级编程语言使用，如上篇文章中的Python；<br>本篇发布前，本人也使用Python写了6个常见的模型，包括正算、反算，但由于Python的UI方面没有过多的知识储备，<br>导致Python始终是使用命令行终端来呈现的... 总之难用就对了，而且终端的话无法做到批量的数据正算、反算；<br>这里也放出Python的GitHub项目地址：<a href="https://github.com/XiaM-Admin/Auto_Si9000_Py">Auto_Si9000_Py</a>，仅供学习参考；<br>以上这就是我转换到.NET C# WPF编写的原因；</p><h2>Auto_Si9000 功能</h2><p>1、支持常见的8个阻抗模型：<br>外层单线不对地,外层单线对地,<br>内层单线不对地,内层单线对地,<br>外层双线不对地,外层双线对地,<br>内层双线不对地,内层双线对地；</p><p>2、支持批量阻抗的正算、反算；</p><p>3、支持生成原生的Si9000软件界面的预览图，并支持复制到剪贴板；<br>预览图中还圈出了重要的数据，如线宽、线距、对地数据，用于EQ的建议；</p><h2>软件截图</h2><p>程序主界面：<br><img src="https://image.180402.xyz/2025/01/12/678389db06bbd.png" alt="1736673754308.png" title="1736673754308.png"></p><p>预览界面：<br><img src="https://image.180402.xyz/2025/01/12/678389f5d6580.png" alt="1736673781214.png" title="1736673781214.png"></p><p>支持复制到剪贴板：<br><img src="https://image.180402.xyz/2025/01/12/67838a24dc27b.png" alt="1736673828246.png" title="1736673828246.png"></p><h2>项目地址</h2><p><a href="https://github.com/XiaM-Admin/Auto_Si9000_WPF"><a href="https://github.com/XiaM-Admin/Auto_Si9000_WPF">https://github.com/XiaM-Admin/Auto_Si9000_WPF</a></a><br>如果帮助到你，可以点一个小小的Star哦~</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/103/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - 判断当前环境是Debug还是Release</title>
<link>https://blog.x-tools.top/archives/67/</link>
<guid>https://blog.x-tools.top/archives/67/</guid>
<pubDate>Wed, 28 Sep 2022 02:26:36 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[最近在软件开发和发布过程中遇到了这样的烦恼：开发过程是在Debug模式下写的，需要与服务器对接一个指定的调试指令，才能正常调试。但是在发布时，需要手动将指令接口换成用户使用环境,切换至Relea...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p><strong>最近在软件开发和发布过程中遇到了这样的烦恼：</strong></p><ol><li>开发过程是在Debug模式下写的，需要与服务器对接一个指定的调试指令，才能正常调试。</li><li>但是在发布时，需要手动将指令接口换成用户使用环境,切换至Release环境编译生产软件才可。</li><li>这就导致，如果说，忘记了自己切换，这就影响了用户体验。</li></ol><p><strong>那么怎么改成自动？</strong><br>我需要使用编译预处理指令<code>#if</code>等操作，<br>如下：</p><pre><code class="lang-csharp">#if DEBUG
    Console.WriteLine(&quot;Debug模式&quot;);//调试环境
#else
    Console.WriteLine(&quot;Release模式&quot;);//生产发布环境
#endif</code></pre><p>这就能做到在切换发布环境时，编译器自动编译相应的代码了。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/67/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - 硬件信息查询监控</title>
<link>https://blog.x-tools.top/archives/55/</link>
<guid>https://blog.x-tools.top/archives/55/</guid>
<pubDate>Thu, 04 Aug 2022 15:45:47 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[说明本篇文章采用第三方开源库openhardwaremonitor来辅助编写查询信息，并且网上大多都是采用这种方式监控硬件信息。常用的硬件信息有：温度、时钟频率、电压、内存占用、存储空间占用、网...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h1>说明</h1><p>本篇文章采用第三方开源库<code>openhardwaremonitor</code>来辅助编写查询信息，并且网上大多都是采用这种方式监控硬件信息。<br>常用的硬件信息有：温度、时钟频率、电压、内存占用、存储空间占用、网络传输状态···<br>这里仅获取到CPU温度以及GPU温度，其他查询方式类似，自己琢磨...</p><h1>一.下载第三方库</h1><p><strong>下载方式：</strong></p><ol><li>项目开源地址：<a href="https://github.com/hexagon-oss/openhardwaremonitor">https://github.com/hexagon-oss/openhardwaremonitor</a>，自己去releases中下载最新版本<br>并且自己编译好后，找到生成文件夹中的<code>OpenHardwareMonitorLib.dll</code>，我们就使用它！</li><li>这里提供文章的第三方dll文件<a href="https://b.x-tools.top/typecho/uploads/2022/08/787440883.rar">OpenHardwareMonitorLib.rar</a>，解压打开即可(Ver：0.9.7.11)</li></ol><h1>二.引用dll文件</h1><ol><li>如图打开项目 - 右键引用 - 添加引用<br> <img src="http://cdn.x-tools.top/MarkDownImg/20228484955154.png" alt="" title=""></li><li>点击"浏览" - 选中下载解压好的dll文件即可。</li></ol><h1>三.使用</h1><ol><li><p>这里首先引用命名空间</p><pre><code class="lang-csharp">using OpenHardwareMonitor.Hardware;
using System;</code></pre></li><li><p>然后复制粘贴下面的类</p><pre><code class="lang-csharp"> public class UpdateVisitor : IVisitor
 {
     public void VisitComputer(IComputer computer)
     {
         computer.Traverse(this);
     }

     public void VisitHardware(IHardware hardware)
     {
         hardware.Update();
         foreach (IHardware subHardware in hardware.SubHardware)
             subHardware.Accept(this);
     }

     public void VisitSensor(ISensor sensor) { }

     public void VisitParameter(IParameter parameter) { }
 }

 public class ComputerCore
 {
     private UpdateVisitor updateVisitor = new UpdateVisitor();
     private Computer computer = new Computer();

     public ComputerCore()
     {
         computer.Open();
         computer.CPUEnabled = true;//开启CPU信息监控
         computer.GPUEnabled = true;//开启GPU信息监控
         computer.Accept(updateVisitor);
     }

     /// &lt;summary&gt;
     /// 获取CPU温度
     /// &lt;/summary&gt;
     /// &lt;returns&gt;&lt;/returns&gt;
     public float GetCpuTemp()
     {
         computer.Accept(updateVisitor);
         float num = 0;
         float cc = 0;
         float avg = 0;
         for (int i = 0; i &lt; computer.Hardware.Length; i++)
         {
             //查找硬件类型为CPU
             if (computer.Hardware[i].HardwareType == HardwareType.CPU)
             {
                 for (int j = 0; j &lt; computer.Hardware[i].Sensors.Length; j++)
                 {
                     //找到温度传感器
                     if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
                     {
                         if (computer.Hardware[i].Sensors[j].Value is null)
                             continue;

                         num += (float)computer.Hardware[i].Sensors[j].Value;
                         if((float)computer.Hardware[i].Sensors[j].Value!=0)
                             cc++;
                         avg = num / cc;
                     }
                 }
             }
         }
         return avg;
     }

     /// &lt;summary&gt;
     /// 获取GPU温度
     /// &lt;/summary&gt;
     /// &lt;param name=&quot;isNva&quot;&gt;是不是英伟达GPU&lt;/param&gt;
     /// &lt;returns&gt;&lt;/returns&gt;
     public float GetGpuTemp(bool isNva = true)
     {
         computer.Accept(updateVisitor);
         HardwareType type = isNva ? HardwareType.GpuNvidia : HardwareType.GpuAti;

         for (int i = 0; i &lt; computer.Hardware.Length; i++)
         {
             //查找硬件类型为CPU
             if (computer.Hardware[i].HardwareType == type)
             {
                 for (int j = 0; j &lt; computer.Hardware[i].Sensors.Length; j++)
                 {
                     //找到温度传感器
                     if (computer.Hardware[i].Sensors[j].SensorType == SensorType.Temperature)
                     {
                         if (computer.Hardware[i].Sensors[j].Value is null)
                             continue;

                         return (float)computer.Hardware[i].Sensors[j].Value;
                     }
                 }
             }
         }
         return 0;
     }

 }
</code></pre></li><li>调用即可<br>实例化：<code>public ComputerCore CCore= new ComputerCore();</code><br>CPU温度：<code>CCore.GetCpuTemp()</code><br>GPU温度：<code>CCore.GetGpuTemp()</code>(英伟达显卡) - <code>CCore.GetGpuTemp(false)</code>(非英伟达显卡)</li></ol><h1>注意</h1><ul><li>项目框架的Framework 版本要求 4.8</li><li>引用后直接使用会出错，这里需要下载一个NuGet包<br><img src="http://cdn.x-tools.top/MarkDownImg/20228485425449.png" alt="" title=""><br>作者使用的就是5.0.0版本，我也就没找事，用最新版。可自行测试。</li><li>CPU温度因为有很多内核 每个内核温度不一样，所以我取了平均值。</li></ul>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/55/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - HotKey热键编写</title>
<link>https://blog.x-tools.top/archives/49/</link>
<guid>https://blog.x-tools.top/archives/49/</guid>
<pubDate>Sun, 10 Jul 2022 15:18:54 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[热键是什么？热键即快捷键，就是键盘上某几个特殊键组合起来完成一项特定任务。笔记本电脑上最常见的热键组合即Fn键加其他键(能够与Fn进行组合使用的键多被用特殊颜色标记，并以图示或文字显示其功能在键...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h1>热键是什么？</h1><blockquote>热键即快捷键，就是键盘上某几个特殊键组合起来完成一项特定任务。笔记本电脑上最常见的热键组合即Fn键加其他键(能够与Fn进行组合使用的键多被用特殊颜色标记，并以图示或文字显示其功能在键帽上)的组合，可被用来设定系统参数，如扬声器音量。</blockquote><p>现在很多程序都离不开快捷键，只需要按下某组合键，就能触发一些事件，如window中的复制粘贴键，只用Ctrl+C、V就可以快捷操作，不需要右键再复制粘贴。<br>快捷键会让程序使用更‘快捷’、‘方便’</p><h1>C# HotKey类</h1><pre><code class="lang-csharp">public class Hotkey
{
    #region 系统api
    [DllImport(&quot;user32.dll&quot;)]
    [return: MarshalAs(UnmanagedType.Bool)]
    static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyModifiers fsModifiers, Keys vk);

    [DllImport(&quot;user32.dll&quot;)]
    static extern bool UnregisterHotKey(IntPtr hWnd, int id);
    #endregion

    /// &lt;summary&gt; 
    /// 注册快捷键 
    /// &lt;/summary&gt; 
    /// &lt;param name=&quot;hWnd&quot;&gt;持有快捷键窗口的句柄&lt;/param&gt; 
    /// &lt;param name=&quot;fsModifiers&quot;&gt;组合键&lt;/param&gt; 
    /// &lt;param name=&quot;vk&quot;&gt;快捷键的虚拟键码&lt;/param&gt; 
    /// &lt;param name=&quot;callBack&quot;&gt;回调函数&lt;/param&gt; 
    public static void Regist(IntPtr hWnd, HotkeyModifiers fsModifiers, Keys vk, HotKeyCallBackHanlder callBack)
    {
        int id = keyid++;
        if (!RegisterHotKey(hWnd, id, fsModifiers, vk))
            throw new Exception(&quot;regist hotkey fail.&quot;);
        keymap[id] = callBack;
    }

    /// &lt;summary&gt; 
    /// 注销快捷键 
    /// &lt;/summary&gt; 
    /// &lt;param name=&quot;hWnd&quot;&gt;持有快捷键窗口的句柄&lt;/param&gt; 
    /// &lt;param name=&quot;callBack&quot;&gt;回调函数&lt;/param&gt; 
    public static void UnRegist(IntPtr hWnd, HotKeyCallBackHanlder callBack)
    {
        foreach (KeyValuePair&lt;int, HotKeyCallBackHanlder&gt; var in keymap)
        {
            if (var.Value == callBack)
                UnregisterHotKey(hWnd, var.Key);
        }
    }

    /// &lt;summary&gt; 
    /// 快捷键消息处理 
    /// &lt;/summary&gt; 
    public static void ProcessHotKey(Message m)
    {
        if (m.Msg == WM_HOTKEY)
        {
            int id = m.WParam.ToInt32();
            HotKeyCallBackHanlder callback;
            if (keymap.TryGetValue(id, out callback))
            {
                callback();
            }
        }
    }

    const int WM_HOTKEY = 0x312;
    static int keyid = 10;
    static Dictionary&lt;int, HotKeyCallBackHanlder&gt; keymap = new Dictionary&lt;int, HotKeyCallBackHanlder&gt;();

    public delegate void HotKeyCallBackHanlder();
}
public enum HotkeyModifiers
{
    MOD_ALT = 0x1,
    MOD_CONTROL = 0x2,
    MOD_SHIFT = 0x4,
    MOD_WIN = 0x8
}</code></pre><p>百度一搜就有...</p><h1>如何使用</h1><p>因为CSharp没有直接的提供热键绑定等操作，所以上面类简单封装了一下Windows系统中user32库的热键api。</p><pre><code class="lang-csharp">[DllImport(&quot;user32.dll&quot;)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool RegisterHotKey(IntPtr hWnd, int id, HotkeyModifiers fsModifiers, Keys vk);

[DllImport(&quot;user32.dll&quot;)]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);</code></pre><p>所以，注册完之后，只要保证程序正常运行，就可以全局触发热键绑定的回调函数。</p><p>使用步骤：</p><ol><li><p>重构消息处理函数</p><pre><code class="lang-csharp">/// &lt;summary&gt;
/// 重构消息处理
/// &lt;/summary&gt;
/// &lt;param name=&quot;m&quot;&gt;&lt;/param&gt;
protected override void WndProc(ref Message m)
{
 base.WndProc(ref m);
 Hotkey.ProcessHotKey(m);
}</code></pre></li><li><p>写一个测试回调函数</p><pre><code class="lang-csharp">void test(){
 MessageBox.Show(&quot;Test&quot;);
}</code></pre></li><li><p>调用注册热键方法</p><pre><code class="lang-csharp">Hotkey.Regist(this.Handle, HotkeyModifiers.MOD_ALT, Keys.X, Test);</code></pre><p>这里注册的热键为"Alt + X"键</p></li><li><p>注销热键方法</p><pre><code class="lang-csharp">Hotkey.UnRegist(this.Handle, Test);</code></pre></li></ol><ul><li>需要注意的是：此回调函数的内存地址不能改变，不能使用lamda表达式，否则不能注销热键！</li></ul>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/49/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - 代码耗时统计</title>
<link>https://blog.x-tools.top/archives/46/</link>
<guid>https://blog.x-tools.top/archives/46/</guid>
<pubDate>Fri, 01 Jul 2022 12:25:56 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[步骤耗时计数命名空间：using System.Diagnostics;类名：Stopwatch stopwatch = new Stopwatch();代码：Stopwatch stopwat...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<h1>步骤耗时计数</h1><ul><li><strong>命名空间：</strong>using System.Diagnostics;</li><li><strong>类名：</strong><code>Stopwatch stopwatch = new Stopwatch();</code></li></ul><p>代码：</p><pre><code class="lang-csharp">Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();                            //开始计时
//
// 放入耗时操作 
//
stopwatch.Stop();                             //结束计时
Console.WriteLine(stopwatch.Elapsed);</code></pre><h1>使用场景</h1><ol><li><strong>程序初始化</strong>用时统计优化</li><li><strong>算法</strong>用时统计优化</li><li><strong>网络请求</strong>用时统计 <strong>api优化</strong></li></ol>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/46/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - 监控监视进程</title>
<link>https://blog.x-tools.top/archives/44/</link>
<guid>https://blog.x-tools.top/archives/44/</guid>
<pubDate>Fri, 24 Jun 2022 14:47:00 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[&lt;!--[toc]--&gt;利用进程监听事件值守进程😘记录自UP：B站知识就是暴力 步骤首先获取进程的信息开启进程的事件接受绑定进程退出后执行的事件完成事件说明如果检测到程序退出了，那么...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>&lt;!--[toc]--&gt;</p><h1>利用进程监听事件值守进程😘</h1><p>记录自UP：B站知识就是暴力<br><iframe src="//player.bilibili.com/player.html?aid=470169457&bvid=BV1fT411G7cb&cid=753677523&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 75%; height: 360px;"> </iframe><br><img src="http://cdn.x-tools.top/MarkDownImg/202262480221103.png" alt="" title=""></p><h2>步骤</h2><ol><li>首先获取进程的信息</li><li>开启进程的事件接受</li><li>绑定进程退出后执行的事件</li><li>完成</li></ol><h2>事件说明</h2><ul><li>如果检测到程序退出了，那么新建一个相同进程</li><li>并且开启事件接受，绑定当前事件</li><li>就做到了一个进程守护的功能</li></ul><h1>WMI 监视进程😘</h1><blockquote>是用于管理基于Windows操作系统的数据和操作的基础结构。</blockquote><p>想法来自：知识就是暴力i</p><p><iframe src="//player.bilibili.com/player.html?aid=642817448&bvid=BV1RY4y1J73k&cid=754478179&page=1" scrolling="no" border="0" frameborder="no" framespacing="0" allowfullscreen="true" style="width: 75%; height: 360px;"> </iframe></p><h2>微软介绍文档</h2><p><img src="http://cdn.x-tools.top/MarkDownImg/202262480571456.png" alt="" title=""></p><h2>使用步骤</h2><ol><li>引用包 <code>using System.Management;</code></li><li>创建查询对象，wql的事件查询，参1：事件名 参2：查询间隔 参3：条件语句</li></ol><p><img src="http://cdn.x-tools.top/MarkDownImg/202262480957289.png" alt="" title=""></p><ol start="3"><li>new 事件监听对象</li></ol><p><img src="http://cdn.x-tools.top/MarkDownImg/202262481001764.png" alt="" title=""></p><ol start="4"><li>注册事件</li></ol><p><img src="http://cdn.x-tools.top/MarkDownImg/202262481206470.png" alt="" title=""></p><p><img src="http://cdn.x-tools.top/MarkDownImg/202262481251841.png" alt="" title=""></p><ol start="5"><li>开始异步侦听</li></ol><p><img src="http://cdn.x-tools.top/MarkDownImg/202262481361927.png" alt="" title=""></p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/44/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp  - Post请求宝塔邮局发件api问题</title>
<link>https://blog.x-tools.top/archives/39/</link>
<guid>https://blog.x-tools.top/archives/39/</guid>
<pubDate>Sun, 19 Jun 2022 12:30:04 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[&lt;!--[toc]--&gt;描述简单描述一下问题：使用C#发送POST请求给宝塔邮局发邮件的api时，出现错误代码500,在ApiPost6、Python官方示例中，请求可以正确发送，返...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>&lt;!--[toc]--&gt;</p><h1>描述</h1><p>简单描述一下问题：<br><strong>使用C#发送POST请求给宝塔邮局发邮件的api时，出现错误代码500,</strong><br><strong>在ApiPost6、Python官方示例中，请求可以正确发送，返回200。</strong></p><h1>正常的POST代码</h1><pre><code class="lang-csharp">public static string ApiPost(string url, Dictionary&lt;string, string&gt; parameters)
{
    try
    {
        Encoding charset = Encoding.UTF8;
    
        HttpWebRequest request = null;
        //HTTPSQ请求
        ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
        request = (HttpWebRequest)WebRequest.Create(url.Trim());
        request.Method = &quot;POST&quot;;
        request.ContentType = &quot;application/x-www-form-urlencoded&quot;;

        //如果需要POST数据
        if (!(parameters == null || parameters.Count == 0))
        {
            var buffer = new StringBuilder();
            foreach (var key in parameters.Keys)
            {
                string str = System.Web.HttpUtility.UrlEncode(parameters[key]);
                buffer.AppendFormat(buffer.Length &gt; 0 ? &quot;&amp;{0}={1}&quot; : &quot;{0}={1}&quot;, key, str);
            }
        
            byte[] data = charset.GetBytes(buffer.ToString());
            request.ContentLength = data.Length;
            request.GetRequestStream().Write(data, 0, data.Length);
        }
        HttpWebResponse response;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
        }
        catch (WebException ex)
        {
            response = (HttpWebResponse)ex.Response;
        }
        Stream htmlStream = response.GetResponseStream();
        StreamReader sr = new StreamReader(htmlStream, Encoding.UTF8);
        var html = sr.ReadToEnd();
        return html;
    }
    catch (Exception e)
    {
        Console.WriteLine($&quot;api:{url} 异常：{e.Message}&quot;);
        return null;
    }
}</code></pre><h1>分析</h1><p>使用<code>Fiddler</code>抓包工具，抓取正常200和错误500的，进行比较，发现<br>C#在POST请求是自动加上了<code>request.Expect</code>这个表头的属性，我们只需要把它去掉就行，<br>去掉后有几率会发送请求失败，需要加入一个错误重试，就能增大请求成功几率。</p><h1>修改过后的代码</h1><blockquote>此代码即可正常请求宝塔邮局发邮件的api</blockquote><pre><code class="lang-csharp">public static string ApiPost(string url, Dictionary&lt;string, string&gt; parameters)
{
    //重试3次
    int recount = 0;
    while(recount &lt; 3)
        try
        {
            Encoding charset = Encoding.UTF8;
        
            HttpWebRequest request = null;
            //HTTPSQ请求
            ServicePointManager.ServerCertificateValidationCallback = CheckValidationResult;
            request = (HttpWebRequest)WebRequest.Create(url.Trim());
            request.Method = &quot;POST&quot;;
            request.ContentType = &quot;application/x-www-form-urlencoded&quot;;
            request.UserAgent = DefaultUserAgent;
            request.Accept = &quot;*/*&quot;;
            request.Expect = null;
            //如果需要POST数据
            if (!(parameters == null || parameters.Count == 0))
            {
                var buffer = new StringBuilder();
                foreach (var key in parameters.Keys)
                {
                    string str = System.Web.HttpUtility.UrlEncode(parameters[key]);
                    buffer.AppendFormat(buffer.Length &gt; 0 ? &quot;&amp;{0}={1}&quot; : &quot;{0}={1}&quot;, key, str);
                }
            
                byte[] data = charset.GetBytes(buffer.ToString());
                request.ContentLength = data.Length;
                request.GetRequestStream().Write(data, 0, data.Length);
            }
            HttpWebResponse response;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException ex)
            {
                response = (HttpWebResponse)ex.Response;
                recount++;
                continue;
            }
            Stream htmlStream = response.GetResponseStream();
            StreamReader sr = new StreamReader(htmlStream, Encoding.UTF8);
            var html = sr.ReadToEnd();
            return html;
        }
        catch (Exception e)
        {
            Console.WriteLine($&quot;api:{url} 异常：{e.Message}&quot;);
            recount++;
            continue;
        }
    return null;
}</code></pre>
]]></content:encoded>
<slash:comments>1</slash:comments>
<comments>https://blog.x-tools.top/archives/39/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
<item>
<title>CSharp - 委托</title>
<link>https://blog.x-tools.top/archives/19/</link>
<guid>https://blog.x-tools.top/archives/19/</guid>
<pubDate>Mon, 30 May 2022 11:54:00 +0000</pubDate>
<dc:creator>小夏</dc:creator>
<description><![CDATA[&lt;!-- [toc] --&gt;委托（Delegate）委托（Delegate）就是一个引用变量，委托（Delegate）特别用于实现事件和回调方法。声明委托// 一个参数一个返回值的委...]]></description>
<content:encoded xml:lang="zh-CN"><![CDATA[
<p>&lt;!-- [toc] --&gt;</p><h1>委托（Delegate）</h1><p>委托（Delegate）就是一个<strong>引用变量</strong>，</p><p>委托（Delegate）特别用于实现事件和回调方法。</p><h2>声明委托</h2><pre><code class="lang-csharp">// 一个参数一个返回值的委托声明
public delegate int MyDelegate (string s);
//无返回值 一个object参数的委托声明
public delegate void MyDelegate (object s);</code></pre><p>上例子声明了一个，一个参数一个返回值的委托函数。</p><p>声明形式：</p><pre><code class="lang-csharp">delegate &lt;return type&gt; &lt;delegate-name&gt; &lt;parameter list&gt;</code></pre><h2>实例化委托</h2><p>委托必须使用 <code>new</code> 关键字来创建，并且new 的构造函数中，必须有一个特定的方法，其方法的形参返回值与委托声明相同，如：</p><pre><code class="lang-csharp">public delegate void printString(string s);
...
printString ps1 = new printString(WriteToScreen);
printString ps2 = new printString(WriteToFile);</code></pre><p>上面的实例化的ps1 和 ps2 ，可以当做函数来调用。</p><h2>委托的多播</h2><p>一个委托对象，可以使用 <code>+</code> 来绑定多个委托实例，所有委托实例参数必须相同，同样，也可以使用<code>-</code>来解除绑定。</p><p>绑定过后，使用委托对象使用，函数方法调用队列，是和绑定顺序相同的执行方式，通过<code>+</code>来绑定的实例委托是一个调用列表。这被称为委托的 <strong>多播（multicasting）</strong>，也叫组播。</p><pre><code class="lang-csharp">using System;

delegate int NumberChanger(int n);
namespace DelegateAppl
{
   class TestDelegate
   {
      static int num = 10;
      public static int AddNum(int p)
      {
         num += p;
         return num;
      }

      public static int MultNum(int q)
      {
         num *= q;
         return num;
      }
      public static int getNum()
      {
         return num;
      }

      static void Main(string[] args)
      {
         // 创建委托实例
         NumberChanger nc;
         NumberChanger nc1 = new NumberChanger(AddNum);
         NumberChanger nc2 = new NumberChanger(MultNum);
         nc = nc1;
         nc += nc2;
         // 调用多播
         nc(5);
         Console.WriteLine(&quot;Value of Num: {0}&quot;, getNum());
         Console.ReadKey();
      }
   }
}</code></pre><h2>委托用途</h2><pre><code class="lang-csharp">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(&quot;The String is: {0}&quot;, str);
      }
      // 该方法打印到文件
      public static void WriteToFile(string s)
      {
         fs = new FileStream(&quot;c:\\message.txt&quot;, FileMode.Append, FileAccess.Write);
         sw = new StreamWriter(fs);
         sw.WriteLine(s);
         sw.Flush();
         sw.Close();
         fs.Close();
      }
      // 该方法把委托作为参数，并使用它调用方法
      public static void sendString(printString ps)
      {
         ps(&quot;Hello World&quot;);
      }
      static void Main(string[] args)
      {
         printString ps1 = new printString(WriteToScreen);
         printString ps2 = new printString(WriteToFile);
         sendString(ps1);
         sendString(ps2);
         Console.ReadKey();
      }
   }
}</code></pre><p>下面的实例演示了委托的用法。委托 <em>printString</em> 可用于引用带有一个字符串作为输入的方法，并不返回任何东西。</p><p>我们使用这个委托来调用两个方法，第一个把字符串打印到控制台，第二个把字符串打印到文件。</p>
]]></content:encoded>
<slash:comments>0</slash:comments>
<comments>https://blog.x-tools.top/archives/19/#comments</comments>
<wfw:commentRss>https://blog.x-tools.top/feed/category/CSharp/</wfw:commentRss>
</item>
</channel>
</rss>