aardio + .NET 快速開發獨立 EXE 程式,可防 ILSpy 反編譯

来源:https://www.cnblogs.com/aardio/archive/2022/09/08/16669034.html
-Advertisement-
Play Games

▶ 簡介 aardio 可以非常方便地調用 .NET( 不需要任何複雜的步驟 )。 .NET 在 aardio 中很好用,系統自帶 .NET 組件以及各種開源 .NET 組件在 aardio 用戶中也很受歡迎。 aardio + .NET 生成的 EXE —— 可避免被 ILSpy 直接反編譯。 a ...


簡介

aardio 可以非常方便地調用 .NET( 不需要任何複雜的步驟 )。

.NET 在 aardio 中很好用,系統自帶 .NET 組件以及各種開源 .NET 組件在 aardio 用戶中也很受歡迎。

aardio + .NET 生成的 EXE —— 可避免被 ILSpy 直接反編譯。

aardio 調用 .NET 示例:

//導入 .NET 支持庫
import dotNet;
 
//導入.NET 程式集
dotNet.import("System"); 

//調用類的靜態成員函數
var isValidHost = System.Uri.CheckHostName("www.aardio.com"); 

//構造 .NET 對象
var uri = System.Uri("https://www.aardio.com/test?q=aardio");

//讀或寫 .Net 對象的實例屬性
var host = uri.Host;

//調用 .Net 對象實例的成員函數
var hash = uri.GetHashCode();

aardio 語法與 JavaScript 接近,請參考:aardio 編程語言快速入門——語法速覽

aardio + .Net 開發對 .NET 版本沒有嚴格要求 —— 相容流行 Windows 系統自帶的不同版本 .NET。不但可以調用系統自帶的大量 .NET 組件,也可以生成體積很小的 EXE 文件。

Win7 自帶 .Net 3.5.1,支持 lambda

Win8 自帶 .Net 3.5.1 + .Net 4.5

Win10 自帶 .Net 4.6

Win10 1709 自帶 .Net 4.7.1 ,支持 ValueTuple

Win11 自帶 .NET 4.8

▶ 記憶體載入 .NET 程式集,生成獨立 EXE

aardio 提供 dotNet.reference() 函數 —— 可以方便地通過記憶體數據載入 .NET 程式集,這樣就可以生成獨立 EXE 程式,不再需要帶上一堆 DLL 文件。

將記憶體數據綁定為 .NET 程式集示例:

import dotNet;

dotNet.reference({
  ["test.mydll"] = $"\test.mydll.dll";
  ["test.core"] = $"\test.core.dll"; 
});

dotNet.reference() 的第 1 個參數指定程式集名稱,第 2 個參數指定實際要載入的程式集路徑或記憶體數據,aardio 代碼在文件路徑前加 $ 號可將文件數據編譯為二進位字元串( 發佈後不再需要原文件 )。

然後就可以正常導入記憶體程式集了,代碼如下:

dotNet.import("test.mydll");

上面的代碼導入 .NET 程式集,然後再將 .NET 名字空間導入 aardio ,dotNet.import() 函數的作用與下麵的代碼相同:

//導入 .NET 程式集
var assembly = dotNet.load("test.mydll"); 

//導入 .NET 名字空間
assembly.import("test.mydll");

▶ aardio 標準庫提供的 .NET 庫

aardio 標準庫中已經提供了一些 .NET 庫,例如 System ,調用示例:

//導入 .NET 名空間
import System; 

//用 System 名字空間下麵的類構造對象實例
var uri = System.Uri("https://www.aardio.com/test?q=aardio")

//讀或寫 .Net 對象的實例屬性
var host = uri.Host ;

aardio 代碼一般使用小駝峰命名風格,但 .NET 名字空間或類名一般會大寫首字母以示區別。

我們右鍵點 System ,在彈出菜單內點擊「跳轉到定義」看一下 System 庫的源代碼。

 可以看到這個 Sytem 庫的關鍵代碼只有兩句:

import dotNet;
dotNet.import("System")

▶ 嵌入 .NET 視窗控制項到 aardio 視窗

aardio 視窗嵌入 .NET DataGridView 控制項範例的運行效果:

 首先要瞭解 .Net 的所有控制項都應當放在 .Net 創建的視窗里(也就是 System.Windows.Forms.Form 對象),視窗是管理控制項的容器,不能直接把控制項單獨擰出來往 aardio 視窗里扔。

如果不想去弄個視窗,aardio 提供了一個更簡單的方法 ,例如把 .Net 的 DataGridView 控制項直接嵌入 aardio 視窗:

import System.Windows.Forms;

var Forms = System.Windows.Forms; 
var dataGridView = Forms.CreateEmbed("DataGridView",winform.custom);

非常簡單。

好了,現在創建 DataTable 數據表,準備把他顯示到控制項里,先創建數據列,重點看怎麼指定列欄位使用的數據類型:

//添加數據列
var dataTable = System.Data.DataTable("DT"); 
dataTable.Columns.Add("名稱");//添加列
dataTable.Columns.Add("計數",System.Type.GetType("System.Double")); //添加指定數據類型的列
dataTable.Columns.Add("選擇",System.Type.GetType("System.Boolean")); //自動顯示覆選框 

然後綁定數據源到視圖:

//綁定數據源到視圖
var dataView = System.Data.DataView(dataTable);
dataGridView.DataSource = dataView;
dataGridView.EditMode=2;

好吧,想再加一個下拉框嗎?!這個就略有些麻煩了,代碼如下:

//先移除自動生成的列
dataGridView.Columns.Remove("名稱"); 

//下麵添加下拉框以替換上面移除的列
var cmbColumn = Forms.DataGridViewComboBoxColumn();
cmbColumn.Width = 120; 
cmbColumn.Name = "Name";
cmbColumn.DataPropertyName  = "名稱";//對應上面 dataTable 里的欄位名
cmbColumn.HeaderText = "名稱"; //顯示在列標題里的文本
 
//如果名稱與顯示值一樣,那直接給 cmbColumn.DataSource 賦值一個數組就可以
//下麵綁定下拉候選框的數據源,上面的 DataPropertyName 才是真正要讀寫的數據值。
cmbColumn.DisplayMember = "Name";//下拉框顯示文本的屬性名
cmbColumn.ValueMember = "Value"; //下拉框選項值的屬性名
cmbColumn.DataSource = dotNet.createNameValueList(
  { "王五","張三"},
  { "WangWu","ZhangSan"}
);

//添加這個新的下拉框到數據視圖
dataGridView.Columns.Add(cmbColumn);

//移動到第一列
dataGridView.Columns.Item["Name"].DisplayIndex = 0;

然後添加下麵的代碼響應 .NET 控制項的事件:

//添加事件(event)
dataTable.ColumnChanged = function(sender,eventArgs){
  var columnName = eventArgs.Column.ColumnName;
  var value  = eventArgs.Row.getItem(columnName);  
  winform.edit.print("已改變列:",columnName," 已變更值:",value);
}

然後讀寫數據:

//添加測試數據
var row = dataTable.NewRow(); 
row.ItemArray = {"WangWu",123, true}
dataTable.Rows.Add(row);   

//讀取數據
winform.button.oncommand = function(id,event){ 
 
  for(i=1;dataTable.Rows.Count;1){ 
     var arr = dataTable.Rows[i].ItemArray; 
     winform.edit.print( arr[1] )  ; 
  } 
}

以上完整範例源代碼請參考 aardio 自帶範例:

aardio 範例 / 調用其他語言 / .Net / 控制項視窗 / 嵌入控制項

 

可以看到 aardio 自帶了大量調用 .NET 的範例。

▶ 在 aardio 中載入的 .NET 程式集如何調試

用下麵的代碼在 aardio 中載入 .NET 程式集的 pdb 調試文件:

dotNet.loadFile( "程式集路徑" ,"pdb 調試文件路徑" ); 

然後用 VS 附加運行的 aardio 進程就可以調試了,懂 .NET 的都懂,這個不多說了。

▶ 用 aardio 在運行時編譯 C# 源碼

直接看 aardio 代碼示例:

import dotNet; 

//創建 C# 語言編譯器
var compiler = dotNet.createCompiler("C#");

//DLL 程式集要提前引入,System.dll 預設已引入,註意這函數不支持記憶體 DLL
compiler.Reference("System.dll");

//設置待編譯C#源碼( 註釋可賦值為字元串,註釋標記首尾星號數目要一致 )
compiler.Source = /*** 
?> 
/*
如果 C# 代碼開始於 aardio 模板標記,則啟用 aardio 模板語法。
參考:《aardio 使用手冊 / aardio 語言 / 模板語法》
*/

namespace CSharpLibrary  
{  
    public class Object  
    {     
        <? if _WINXP { ?> 
        public string Test(){    
            return "Windows XP"; 
        }
        <? } else { ?> 
        public string Test(){    
            return "<?= win.version.name ?>"; 
        }
        <? } ?> 
    }   
} 
***/
import win.version;

//編譯並返回程式集,可選在參數中指定輸出 DLL文件,不指定則編譯為記憶體程式集。
var assembly = compiler.CompileOrFail(/*"/output.dll"*/);  

//導入名字空間,也可以直接寫 compiler.import("CSharpLibrary"); 
assembly.import("CSharpLibrary");  

//使用 C# 編寫的類構造對象實例 
var netObj = CSharpLibrary.Object();

//調用實時編譯的C#函數
var ret = netObj.Test(); 

import console;
console.log( ret );
console.pause();

註意 aardio 中的註釋可賦值為字元串,因為 aardio 要求段註釋的首尾星號數目必須一致,所以不會與其他編程語言衝突,很適合用來放其他編程語言的源代碼。

上面的 compiler.Source 可以用一個字元串指定 C# 源碼,這個字元串支持類似 PHP 的模板語法,所以我們可以用 aardio 代碼靈活地在運行時生態生成比較複雜的 C# 源代碼,然後再用 .NET 編譯為程式集。aardio 中的 dotNet.desktop 擴展庫就使用了這種技術用很少的代碼就實現了虛擬桌面管理支持庫。

預設可以將 C# 源碼編譯為記憶體程式集,這樣很適合生成獨立 EXE 文件。

註意在 aardio 中編譯 C#,調用的是 CLR,而 CLR 只有 2.0 / 4.0 的區別,運行時編譯也只支持這兩個版本的語法。例如安裝了 .Net 3.5 但沒有安裝 .Net 4.x ,那麼 CLR 2.0 下編譯器不支持 var ,lambda 這些語法 (但是能運行編譯後的 DLL,可以事先用 VS 編譯 C# 代碼生成 DLL 程式集)。

▶ .NET 與 aardio 對象相互轉換規則

aardio 會自動處理類型轉換,調用 .NET 函數時如果參數類型不一致 —— aardio 也會盡最大可能地轉換參數類型,用起來還是比較輕鬆的。但簡單瞭解一下類型轉換規則和原理是有必要的。

所有原生 .NET 對象在 aardio 中分為兩類:

1、可自動轉換的簡單值類型

null值、數值、字元串、枚舉、 System.Drawing.Color 等簡單值類型,以及這些值類型的數組可以直接交換。aardio 中的 buffer 在 .NET 中對應位元組數組。

2、在 aardio 中存為 COM 對象的 .NET 對象

其他原生 .NET 對象在 aardio 存為 com.NETObject 對象(對應 .NET 中的 System.__ComObject 類型),其中有些特殊的 .NET 對象(例如 struct,ValueTuple),在傳入 aardio 時會封包為特殊的 DispatchableObject 對象。這些 .NET 對象在 aardio 中都會被封裝為 dotNet.object 對象,在 aardio 中使用沒有太大區別。

aardio 與 .NET 交互基於 COM 介面,所以遵守 aardio 的 COM 傳參基本規則:

aardio 中的整數傳入 .NET 預設為 int32,小數預設為 double 類型。aardio 數值數組傳入 .NET 預設為 double 類型 COM 數組,純字元串數組一律轉為 BSTR 數組。其他數組轉為 Variant 變體類型數組。

.NET 中的 enum 枚舉會自動轉換為 aardio 中的數值(雙向自動轉換),

.NET 中的 struct,tuple 由 .NET 對象 DispatchableObject 封包後再返回 aardio 。

aardio 函數則自動轉換為委托、事件所需要的委托類型。

.NET 中的 System.IntPtr,System.UIntPtr 類型在 aardio 中會自動轉換為整數值,

aardio 中的指針類型(pointer)必須使用 tonumber() 函數轉換為數值才能傳入 .NET。

視窗句柄( HWND ) 在 aardio 以整數值表示,可以直接傳入 .NET。

System.Drawing.Color 在 aardio 則會自動轉換為 ARGB 格式的顏色數值。

調用 .NET 時 ARGB 格式的顏色數值也能自動轉換為 System.Drawing.Color 對象。

註意 GDI+ 使用 ARGB 格式顏色值,與 gdip庫,plus 控制項等相容。

aardio 提供以下函數創建指定靜態類型的 dotNet.object 對象:

dotNet.object(value,byRef) 轉換為 .Net 對象。

dotNet.byte(value,byRef) 轉換為 8 位整型數值。

dotNet.ubyte(value,byRef) 轉換為 8 位無符號整型數值。

dotNet.word(value,byRef) 轉換為 16 位整型數值。

dotNet.uword(value,byRef) 轉換為 16 位無符號整型數值。

dotNet.int(value,byRef) 轉換為 32 位整型數值。

dotNet.uint(value,byRef) 轉換為 32 位無符號整型數值。

dotNet.long(value,byRef) 轉換為 64 位整型數值。

dotNet.ulong(value,byRef) 轉換為 64 位無符號整型數值。

dotNet.float(value,byRef) 轉換為 32 位浮點數值。

dotNet.double(value,byRef) 轉換為 64 位浮點數值

以上函數會將參數 1 存為 .NET 對象並封包為 DispatchableObject 對象後再返回 dotNet.object 對象,( 簡單的值類型也會轉換為 dotNet.object 對象 ),這可以讓 aardio 直接引用 .NET 中的對象,方便實現 ref,out 等輸出參數。

下麵的 aardio 代碼演示了 dotNet.object 的用法:

import dotNet; 
var compiler = dotNet.createCompiler("C#");

//指定 C# 源代碼
compiler.Source = /***
namespace CSharpLibrary  
{  
    public class Object  
    {     
        public static void Test(ref double num,int [] arr){   
            num = 12.3;
            arr[0] = 56;
        }
    }   
} 
***/

//編譯程式集並導入名字空間  
compiler.import("CSharpLibrary"); 

//創建 .Net 對象,啟用引用傳參。 
var num = dotNet.double(12.5,true);

//創建 .Net 數組 
var arr = dotNet.int({1,2,3}); 

//調用 .NET 函數。
CSharpLibrary.Object.Test(num,arr); 

import console;

/*
dotNet.object 對象如果存儲的是數組,
可用下標直接讀寫數組成員。
*/
console.log( arr[1] ) 
 
/*
dotNet.object 對象如果存儲的是 Primitive,enum,string 類型
或這些類型的普通數組,則可使用 Value 屬性讀寫原始值。
*/
console.log( num.Value ); 

//支持 tostring() 轉換為字元串,tonumber() 轉換為數值。
console.log(tostring(num),tonumber(num)); 
console.pause();

▶ 下標

C# 中的 下標操作符[] 實際上會被自動轉換為訪問 Item[] 下標屬性。

先看 aardio 代碼示例:

import dotNet;  
var compiler = dotNet.createCompiler("C#");

compiler.Source = /****** 
using System;
using System.Collections.Generic;
namespace CSharpLibrary  
{ 
    public class TestClass
    {
        private Object [] values = new Object [] {1,2,3,4,5,6,7,8,9};
        public Object this [int index]
        {
            get  { return values[index]; }
            set  { values[index] = value; }
        }
        
        public Dictionary<string,string> dict = new Dictionary<string,string> ();
   }
} 
******/ 

//編譯並引入 C# 名字空間
compiler.import("CSharpLibrary"); 

//使用 C# 編寫的類構造對象實例
var netObj = CSharpLibrary.TestClass(); 

//讀下標屬性,按 C# 規則起始下標為0,而非 aardio 中的起始下標為 1。
var item = netObj.Item[5];
var item = netObj.getItem(5); //這樣讀下標屬性也可以,支持多參數
var item = netObj.Item(5); //get 首碼可以省略

//寫下標屬性
netObj.Item[5]  = 123;
netObj.setItem(5); //這樣寫下標屬性也可以,支持多參數

//如果.NET 對象的下標為數值,允許省略 Item,但這時候起始下標為 1。
var item = netObj[6];
 
//也可以下麵這樣賦值:
netObj[6] = 123; 

import console;
console.log(netObj[6]); 

//字典也可以這樣訪問
netObj.dict.Item["test"] = "abc";
console.log( netObj.dict.Item["test"] );

console.pause();

要點:

1、在 aardio 中需要用 Item[] 訪問 .NET 對象的 Item 屬性。這時候要註意起始下標為 0 ( 遵守 C# 規則 )。

2、如果下標為數值可以省略 Item 直接寫 [],但這時要起始下標為 1 (遵守 aardio 規則)。

 調用 UWP

用下麵的 aardio 代碼創建支持調用 UWP 組件的 C# 編譯器:

import dotNet.uwpCompiler  
var uwpCompiler = dotNet.uwpCompiler( "\ocr.dll" )

可選在 dotNet.uwpCompiler 的第 2 個參數指定 Windows.winmd 的路徑,如果沒有指定 aardio 會自動到下麵的目錄去查找最新版本 Windows 10 SDK 目錄( 需要事先安裝 ):

 C:\Program Files (x86)\Windows Kits\10\UnionMetadata 

然後在 SDK 目錄下查找 Windows.winmd。我們只是在編譯程式集時需要 Windows.winmd,運行時不需要它( 也不需要 Windows 10 SDK )。

例如 aardio 標準庫 dotNet.ocr 包含的 ocr.dll 就是用下麵的代碼編譯的:

import dotNet.uwpCompiler  
var uwpCompiler = dotNet.uwpCompiler( "\ocr.dll" )

//啟用編譯優化
uwpCompiler.Parameters.CompilerOptions = "/optimize"
 
//設置待編譯C#源碼
uwpCompiler.Source = /****** 
using System;
using System.Reflection; 
using System.Collections; 
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks; 
using Windows.Graphics.Imaging;
using Windows.Storage;
using Windows.Storage.Streams;
using System.Runtime.InteropServices;
using Windows.Media.Ocr;

namespace aardio  
{ 
    public class UwpOcrResult
    {
    
        public UwpOcrResult(OcrResult ocrRet)
        {
            ocrResult = ocrRet; 
        }
    
        public int LineCount()
        {
            return ocrResult.Lines.Count;
        }
    
        public string [] GetWords(int index)
        {
            ArrayList arr = new ArrayList();
            foreach (var word in ocrResult.Lines[index].Words)
            {
                arr.Add(word.Text);
            }
    
            return (string[])arr.ToArray(typeof(string));
        }
    
        public object GetWordRects(int index)
        {
            ArrayList arr = new ArrayList();
            foreach (var word in ocrResult.Lines[index].Words)
            {
                double[] rc = { word.BoundingRect.Left, word.BoundingRect.Top, word.BoundingRect.Right, word.BoundingRect.Bottom };  
                arr.Add(rc);
            }
    
            return (object)arr.ToArray(typeof(object));
        }
    
        private OcrResult ocrResult;
    
    }
    
    public class UwpOcrEngine  
    {
        public string [] AvailableRecognizerLanguages(){   
            ArrayList arr = new ArrayList();
            foreach (var lang in OcrEngine.AvailableRecognizerLanguages)
            {
                arr.Add(lang.LanguageTag);
            }
            return (string [])arr.ToArray(typeof( string));
        } 
          
        public object IsLanguageSupported( string name ){   
            Windows.Globalization.Language lang = new Windows.Globalization.Language(name);
            return OcrEngine.IsLanguageSupported(lang); 
        }
    
        public UwpOcrResult Recognize(byte[] imgBuffer, string language){   
            return new UwpOcrResult( RecognizeAsync(imgBuffer, language).GetAwaiter().GetResult() );
        }
    
        async Task<OcrResult> RecognizeAsync(byte[] imgBuffer, string language)
        { 
                var randomAccessStream = new InMemoryRandomAccessStream();
                var outputStream = randomAccessStream.GetOutputStreamAt(0);
                var dw = new DataWriter(outputStream);
                var task = new Task(() => dw.WriteBytes(imgBuffer));
                task.Start();
                await task;
                await dw.StoreAsync();
                await outputStream.FlushAsync();
    
                BitmapDecoder decoder = await BitmapDecoder.CreateAsync(randomAccessStream);
                SoftwareBitmap softwareBitmap = await decoder.GetSoftwareBitmapAsync(BitmapPixelFormat.Bgra8, BitmapAlphaMode.Premultiplied);
                Windows.Globalization.Language lang = new Windows.Globalization.Language(language);
    
                OcrEngine engine = OcrEngine.TryCreateFromLanguage(lang);
                if (engine != null)
                {
                    OcrResult ocrResult = await engine.RecognizeAsync(softwareBitmap);
                    return ocrResult;
                }
    
                return null;
        }
    }   
} 
******/

//編譯並返回程式集  
var assembly = uwpCompiler.CompileOrFail();

import console;
if(assembly) console.logPause("編譯成功",uwpCompiler.Parameters.OutputAssembly);

dotNet.ocr 支持庫的體積很小,可以生成獨立 EXE 文件,調用代碼也非常簡潔。下麵是調用 示例:

▶ 更多

aardio 提供的 .NET 範例非常多,更多功能請參考 aardio 自帶範例,如果大家有任何問題可以下麵評論中留言,我會儘快解答。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Spring框架筆記 IOC容器(控制反轉) 什麼是 IOC ​ 控制反轉,把對象創建和對象之間的調用過程,交給Spring進行管理。 使用IOC目的: ​ 降低耦合度 ​ 通過控制反轉,對象在被創建的時候,由一個調控系統內所有對象的外界實體將其所依賴的對象引用傳遞給他。也可以說依賴被註入到對象中。 ...
  • 5. 數據查詢 欲看此文,必看如下兩篇文章: Druid支持JSON-over-HTTP和SQL兩種查詢方式。除了標準的SQL操作外,Druid還支持大量的唯一性操作,利用Druid提供的演算法套件可以快速的進行計數,排名和分位數計算。 5.1 準備工作 5.1.1 導入大量數據 準備大量數據提供查詢 ...
  • 以.uos為尾碼的文件,表示Uniform Office Spreadsheet文件,是一種國產的辦公文件格式,該格式以統一辦公格式(UOF)創建,使用XML和壓縮保存電子錶格。既有的Excel表格文件,可以通過格式轉換的方式轉換為UOS格式,本文將對此作相關介紹。 【導入jar包】 使用jar包: ...
  • 我國目前並未出台專門針對網路爬蟲技術的法律規範,但在司法實踐中,相關判決已屢見不鮮,K 哥特設了“K哥爬蟲普法”專欄,本欄目通過對真實案例的分析,旨在提高廣大爬蟲工程師的法律意識,知曉如何合法合規利用爬蟲技術,警鐘長鳴,做一個守法、護法、有原則的技術人員。 案情介紹 2017年以來,被告人王世傑工作 ...
  • 一、Map的使用 前面我們在Mapper介面的方法中,傳入的參數都是一個基本類型或者是一個實體類,那麼如果我們需要的參數不止一個但又用不到實體類所有的屬性有沒有什麼更好的辦法呢,這裡我們就可以用到Map了。 我們還是以具體的操作來進行理解。 1.利用Map實現查詢 (1)修改UserMapper介面 ...
  • 一、什麼是索引 在mysql中,索引是一種特殊的資料庫結構,由數據表中的一列或多列組合而成,可以用來快速查詢數據表中有某一特定值的記錄。通過索引,查詢數據時不用讀完記錄的所有信息,而只是查詢索引列即可,索引是幫助Mysql高效獲取數據且以排好序的數據結構,直觀的說,索引就類似書的目錄頁,沒有目錄(即 ...
  • 查找 二分查找 時間複雜度:O (logN) 說明:取數組中間的值和查找值進行比較、如果 中間的值大於要查找的值、則高位索引往中間索引-1、小於則是低位索引往上提、即中間索引+1、一直迴圈直至找到值、最後沒有找到則返回-1 /** * 二分查找法 * @return 返回查找的索引、沒有則返回-1 ...
  • 題目 中文 實現一個以 T 作為泛型參數的 IsNever類型. 如果 T 是never, 返回 true, 否則返回 false. 示例: type A = IsNever<never>; // expected to be true type B = IsNever<undefined>; // ...
一周排行
    -Advertisement-
    Play Games
  • GoF之工廠模式 @目錄GoF之工廠模式每博一文案1. 簡單說明“23種設計模式”1.2 介紹工廠模式的三種形態1.3 簡單工廠模式(靜態工廠模式)1.3.1 簡單工廠模式的優缺點:1.4 工廠方法模式1.4.1 工廠方法模式的優缺點:1.5 抽象工廠模式1.6 抽象工廠模式的優缺點:2. 總結:3 ...
  • 新改進提供的Taurus Rpc 功能,可以簡化微服務間的調用,同時可以不用再手動輸出模塊名稱,或調用路徑,包括負載均衡,這一切,由框架實現並提供了。新的Taurus Rpc 功能,將使得服務間的調用,更加輕鬆、簡約、高效。 ...
  • 本章將和大家分享ES的數據同步方案和ES集群相關知識。廢話不多說,下麵我們直接進入主題。 一、ES數據同步 1、數據同步問題 Elasticsearch中的酒店數據來自於mysql資料庫,因此mysql數據發生改變時,Elasticsearch也必須跟著改變,這個就是Elasticsearch與my ...
  • 引言 在我們之前的文章中介紹過使用Bogus生成模擬測試數據,今天來講解一下功能更加強大自動生成測試數據的工具的庫"AutoFixture"。 什麼是AutoFixture? AutoFixture 是一個針對 .NET 的開源庫,旨在最大程度地減少單元測試中的“安排(Arrange)”階段,以提高 ...
  • 經過前面幾個部分學習,相信學過的同學已經能夠掌握 .NET Emit 這種中間語言,並能使得它來編寫一些應用,以提高程式的性能。隨著 IL 指令篇的結束,本系列也已經接近尾聲,在這接近結束的最後,會提供幾個可供直接使用的示例,以供大伙分析或使用在項目中。 ...
  • 當從不同來源導入Excel數據時,可能存在重覆的記錄。為了確保數據的準確性,通常需要刪除這些重覆的行。手動查找並刪除可能會非常耗費時間,而通過編程腳本則可以實現在短時間內處理大量數據。本文將提供一個使用C# 快速查找並刪除Excel重覆項的免費解決方案。 以下是實現步驟: 1. 首先安裝免費.NET ...
  • C++ 異常處理 C++ 異常處理機制允許程式在運行時處理錯誤或意外情況。它提供了捕獲和處理錯誤的一種結構化方式,使程式更加健壯和可靠。 異常處理的基本概念: 異常: 程式在運行時發生的錯誤或意外情況。 拋出異常: 使用 throw 關鍵字將異常傳遞給調用堆棧。 捕獲異常: 使用 try-catch ...
  • 優秀且經驗豐富的Java開發人員的特征之一是對API的廣泛瞭解,包括JDK和第三方庫。 我花了很多時間來學習API,尤其是在閱讀了Effective Java 3rd Edition之後 ,Joshua Bloch建議在Java 3rd Edition中使用現有的API進行開發,而不是為常見的東西編 ...
  • 框架 · 使用laravel框架,原因:tp的框架路由和orm沒有laravel好用 · 使用強制路由,方便介面多時,分多版本,分文件夾等操作 介面 · 介面開發註意欄位類型,欄位是int,查詢成功失敗都要返回int(對接java等強類型語言方便) · 查詢介面用GET、其他用POST 代碼 · 所 ...
  • 正文 下午找企業的人去鎮上做貸後。 車上聽同事跟那個司機對罵,火星子都快出來了。司機跟那同事更熟一些,連我在內一共就三個人,同事那一手指桑罵槐給我都聽愣了。司機也是老社會人了,馬上聽出來了,為那個無辜的企業經辦人辯護,實際上是為自己辯護。 “這個事情你不能怪企業。”“但他們總不能讓銀行的人全權負責, ...