.NET CORE 基礎

来源:https://www.cnblogs.com/zyb-wzy/archive/2022/05/30/dotnet_core.html
-Advertisement-
Play Games

.NET CORE 1.Microsoft Azure 微軟擁抱雲計算 2..net core 是為雲所生的技術 3.Net Framework缺點: 系統級別的安裝,互相影響 無法獨立部署 SAP.NET和IIS深度耦合 非雲原生 4.NET Framework歷史包袱 基於拖控制項之上的MVC A ...


.NET CORE

1.Microsoft Azure 微軟擁抱雲計算

2..net core 是為雲所生的技術

3.Net Framework缺點:

  • 系統級別的安裝,互相影響

  • 無法獨立部署

  • SAP.NET和IIS深度耦合

  • 非雲原生

4.NET Framework歷史包袱

  • 基於拖控制項之上的MVC

  • ASP.NET 底層不支持很好的單元測試

5.NET Core的有點

  • 支持獨立部署不相互影響

  • 徹底模塊化

  • 運行效率高

  • 跨平臺

  • 符合現代開發理念,依賴註入,單元測試等

.NET Core .NET Framework 兩者根據標準實現 .NET Standard 規定的類 規定的方法 只有定義沒有實現 反編譯軟體ILSpy

驗證:.NET Standard只是標準,不是實現1)建.NET Standard類庫項目,確認版本是 2.0,建一個類,方法中列印 typeof (FileStream).Assembly.Location。2分別建NET Framework和.NET Core的控制台項目,添加對類庫項目引用,並且調用。3用反編譯工具ILSpy儘管開源)分別反編譯VS中FileStream、.NET Framework和. NETCore運行中的。BeginRead方法實現以及定義有 不同。

.NET5開發工具:1).NET CLI:命令行 2)yisual Studio: Windows-Only(推薦)3) Visual Studio for Mac 4)Jetbrains Rider:收費 5)vS Code (Visual Studio, Code):跨平臺

.NET SDK、運行時、文檔----https:// dotnet.mi crosoft.com/ 可能VS自帶,但是在伺服器上需要單獨安裝

dotnet —-version查看版本 dotnet new console當前文件夾下創建控制台項目 dotnet run構建並運行 詳細見官方文檔“.NET CLI”部分。

程式的發佈。 1、部署模式:依賴框架;獨立(推薦)﹔ 2、目標運行時。 3、生成單個文件。 4、ReadyToRun: AOT (ahead of-time)、JIT。缺點看文檔。 5、裁剪未使用的程式集。缺點看文檔。 自學就要養成把相關文檔“翻一翻”的意識。

WSL:Windows subsystem for linux SandBox

NugGet

註意:【預設項目】為目標項目。 1)安裝:Install-Package XXX.yersion指定版本。 可以看到把依賴組件都下載了。 版本檢測:嘗試把項目改為.NET core 1.0,然後再安裝Zack. EFCore.Batch試試。 2)卸載:Uninstall-Package XXX 3)更新到最新版:Update-Package XXX

1、NuGet你也可以頁獻,就三步。 2、和.NET Framework不同,.NET core絕大部分官方程式集也要到NuGet下載。模塊化! 3、少部分是收費的,如搜索“word file” 4、參差不齊,如何分辨質量。 5、內部部署NuGet服務mTo

非同步編程1

不等 非同步編程不能加快單個請求的響應速度,只是能處理更多的請求

C#關鍵字:async await 不能與多線程

“非同步方法”:async關鍵字修飾的方法 1))非同步方法的返回值一般是Task<T>,T是真正的返回值類型,Task<int>。慣例:非同步方法名字以Async結尾。 2)即使方法沒有返回值,也最好把返回值聲明為非泛型的Task。 3)調用非同步方法時,一般在方法前加上await,這樣拿到的返回值就是泛型指定的T類型;4)非同步方法的“傳染性”:一個方法中如果有await調用,則這個方法也必須修飾為async

static async Task Main(string[] args)
{
  string fileName = "d:/1.txt" ;File. Delete(fileName) ;
  File.WriteA11TextAsync(fileName,"hello async");string s= await File.ReadAllTextAsync(fileName) ; Console.WriteLine(s):
}

如果同樣的功能,既有同步方法,又有非同步方法,那麼首先使用非同步方法。.NE5中,很多框架的方法也都支持非同步:Main、WinForm事件處理函數。 對於不支持的非同步方法怎麼辦? Wait()(無返回值);Result(有返回值)。風險:死鎖。盡不用

非同步委托

 //線程池  在子線程中執行的方法放到線程池
ThreadPool.QueueUserWorkItem(async(obj) =>
{
    while (true)
    {
    await File.WriteAllTextAsync(@"D:\text\1.txt","aaaaaaaaaaa");
    Console.WriteLine("------------------");
    }
});
Console.Read();

·用ILSpy反編譯dll(.exe只是 windows下的啟動器)成C#4.0版本,就能看到容易理解的底層lL代碼。await、async是“語法糖”,最終編譯成“狀態機調用”.

總結: async的方法會被C#編譯器編譯成一個類,會主要根據await調用進行切分為多個狀態,對async方法的調用會被拆分為對MoveNext的調用。 用await看似是“等待”,經過編譯後,其實沒有“wait”。

            //使用非同步編程獲取百度網址頁面的代碼並且寫道文件中  然後讀出來寫入到控制器
using (HttpClient httpContent = new HttpClient())
          {
              string html = await httpContent.GetStringAsync("https://www.baidu.com");
              Console.WriteLine(html);
          }
          string txt = "hellow zyb";
          string filename = @"D:\text\1.txt";
          await File.WriteAllTextAsync(filename, txt);
          Console.WriteLine("寫入成功");
          string s = await File.ReadAllTextAsync(filename);
          Console.WriteLine("文件內容"+s);

await調用的等待期間,.NET會把當前的線程返回給線程池,等非同步方法調用執行完畢後,框架會從線程池再取出來一個線程執行後續的代碼。

Thread.CurrentThread.ManagedThreadId 獲得當前線程Id

驗證:在耗時非同步(寫入大字元串)操作前分別列印線程Id

 Console.WriteLine(Thread.CurrentThread.ManagedThreadId);  //托管線程id
StringBuilder sb = new StringBuilder(); //大文件
for (int i = 0; i < 2000; i++)  
{
sb.Append("xxxxxxxxxxxxx");   //等待的過程中把當前的線程放到線程池,然後從線程池取出隨機線程執行別的方法
}
await File.WriteAllTextAsync(@"D:\text\1.txt",sb.ToString());
          Console.WriteLine(Thread.CurrentThread.ManagedThreadId); //托管線程id   兩次線程的id不一樣

非同步編程不等於線程

非同步方法的代碼並不會自動在新線程中執行,除非把代碼放到新的線程中執行

用Task.Run改造之前的例子,再看看線程變化

 
  Console.WriteLine("之前", +Thread.CurrentThread.ManagedThreadId);
          double r = await CalcAsync(5000);
          Console.WriteLine($"r={r}");
          Console.WriteLine("之前", +Thread.CurrentThread.ManagedThreadId);
public static async Task<double> CalcAsync(int n)
      {//自動根據返回值進行類型推斷   將下麵代碼放到新的線程執行
          return await Task.Run(() =>
          {
              Console.WriteLine("CalcAsync", +Thread.CurrentThread.ManagedThreadId);
              double result = 0;
              Random radn = new Random();
              for (int i = 0; i < n * n; i++)
              {
                  result += radn.NextDouble();
              }
              return result;
          });
         

      }

anync方法缺點

1.非同步方法會生成一個類,運行效率沒有普通方法高,

2.可能會占用非常多的線程

只甩手Task,不拆完了再裝,反編譯上面的代碼,知識普通方法的調用

有點:運行效率高,不會造成線程浪費

返回值為Task的不一定都要標註async,標註async知識讓我們可以更方便的await而已

如果一個非同步的方法只是對別的方法調用的轉發,並沒有太多的複雜邏輯,(比如等待a的結果,再調用b,把a調用的返回值拿到內部做一些處理再返回),那麼就可以去掉async關鍵字


//內部只是對方法的調用
static Task<string> ReadAsync(int num)
      {
          if (num == 1)
          {
            return File.ReadAllTextAsync(@"D:\text\1.txt");
           
          }
          else if (num == 2)
          {
            return   File.ReadAllTextAsync(@"D:\text\2.txt");
          }
          else
          {
              throw new ArgumentException();
          }

      }

非同步編程 不要用sleep

如果想在非同步方法中暫停一段時間,不要用thread.sleep(),因為他會阻塞調用線程,而要用await task.Delay()

在控制臺中沒看到區別,但是放到winform程式中就能看到區別了,asp.net core中也看不到區別但是sleep()會降低併發

//這是winform的代碼塊
private async void button1_Click(object sender, EventArgs e)
      {
          using (HttpClient httpClient = new HttpClient())
          {
              string sl = await
              httpClient.GetStringAsync("https://www.youzack.com");
              textBox1.Text = sl.Substring(0,20);
              //Thread.Sleep(3000);
              await Task.Delay(3000);
              string s2 = await
              httpClient.GetStringAsync("https://www.baidu.com");
              textBox1.Text = sl.Substring(0, 20);
          }
      }

非同步編程CancellationToken

有時需要提前終止任務,比如:請求超時,用戶取消請求,跟多非同步方法都有CancellationToken參數 用於獲得提前終止的信號

CancellationToken結構體None:空 bool lsCancellationRequested是否取消(*)Register(Action callback)註冊取消監聽ThrowlfCancellationRequested()如果任務被取消,執行到這句話就拋異常。

CancellationTokenSource CancelAfter()超時後發出取消信號Cancel()發出取消信號 CancellationToken Token

為“下載一個網址N次”的方法增加取消功能。 分別用GetStringAsync + IsCancellationRequested、 GetStringAsync+ ThrowlfCancellationRequested()、帶CancellationToken的GetAsync()分別實現。取消分別用超時、用戶敲按鍵(不能await)實現。

ASP.NET Core開發中,一般不需要自己處理CancellationToken、 CancellationTokenSource這些,只要做到“能轉發cancellationToken就轉發”即可。ASP.NET Core會對於用戶請求中斷進行處理。(*)演示一下ASP.NETCore中的使用:寫一個方法,Delay1000次,用 Debug.WriteLine(輸出,訪問中間跳到放到其他網站。

CancellationTokenSource cts = new CancellationTokenSource();
          cts.CancelAfter(2000);
          CancellationToken token = cts.Token;
          await DownloadlAsync("https://www.baidu.com",1000,token);
static async Task DownloadlAsync(string url, int n,CancellationToken cancellationToken)
      {
          using (HttpClient client = new HttpClient())
          {
              for (int i = 0; i < n; i++)
              {
                  var resp = await client.GetAsync(url,cancellationToken);  
                  string html = await resp.Content.ReadAsStringAsync();
                  File.WriteAllTextAsync(@"D:\text\1.txt", html,cancellationToken);
                  Console.WriteLine($"{DateTime.Now}:{html}");
                  //if (cancellationToken.IsCancellationRequested)
                  //{
                  //   Console.WriteLine("請求被取消了");
                  //   break;
                  //}
                  //cancellationToken.ThrowIfCancellationRequested();  
              }
          }
      }
  //CancellationToken cancellationToken  這個參數是為了防止用戶訪問別的網站或者關閉瀏覽器服務端還在執行
static async Task DownloadlAsync(string url, int n, CancellationToken cancellationToken)
{
using (HttpClient client = new HttpClient())
{
for (int i = 0; i < n; i++)
{
var resp = await client.GetAsync(url, cancellationToken);
string html = await resp.Content.ReadAsStringAsync();
Debug.WriteLine(html);
}
}
}

public async Task<IActionResult> Index(CancellationToken cancellationToken)
{
await DownloadlAsync("https://www.baidu.com", 10000, cancellationToken);
return View();
}

非同步編程WhenAll

Task類的重要方法: 1.Task<Task> WhenAny(lEnumerable<Task>tasks)等,任何一個Task完成,Task就完成2.Task<TResult[]> WhenAll<TResult>(paramsTask<TResult>[] tasks)等,所有Task完成,Task才完成。用於等待多個任務執行結束,但是不在乎它們的執行順序。 3.FromResult()創建普通數值的Task對象。

 string[] file = Directory.GetFiles(@"D:\text\1.txt");
Task<int>[] counts = new Task<int>[file.Length];
for (int i = 0; i < file.Length; i++)
{
string fileName = file[i];
Task<int> t = ReadCharCount(fileName);
counts[i] = t;
}
int[] countTask = await Task.WhenAll(counts);
Console.WriteLine(countTask);
static async Task<int> ReadCharCount(string fileName)
{
string a = await File.ReadAllTextAsync(fileName);
return a.Length;

}

非同步編程其他問題

介面中的非同步方法: async是提示編譯器為非同步方法中的await代碼進行分段處理的,而一個非同步方法是否修飾了async對於方法的調用者來講沒區別的,因此對於介面中的方法或者抽象方法不能修飾為async。


interface IText
{

Task<int> GetCharCount(string file);
}

class Text : IText
{
public async Task<int> GetCharCount(string file)
{
string a = await File.ReadAllTextAsync(file);
return a.Length;
}
}

非同步與yield: 複習: yield return不僅能夠簡化數據的返回,而且可以讓數據處理“流水線化”,提升性能。

  foreach (var s in Test2())
{
Console.WriteLine(s);
}
static IEnumerable<string> Test2()
{
yield return "hellow"; //這裡直接返回一條進行foreach迴圈 取一條執行一條 方法內部拆分搞成狀態機
yield return "yzk";
yield return "youzack";

}

在舊版C#中,async方法中不能用yield。從C#8.0開始,把返回值聲明為IAsyncEnumerable(不要帶Task),然後遍歷的時候用await foreach()即可。

  await foreach (var s in Test3())
{
Console.WriteLine(s);
}
static async IAsyncEnumerable<string> Test3()
{
yield return "hellow";
yield return "yzk";
yield return "youzack";
}

為什麼要學LING

為什麼要學LINQ?讓數據處理變得簡單: 讓數據處理傻瓜化 統計一個字元串中每個字母出現的頻率(忽略大小寫),然後按照從高到低的順序輸出出現頻率高於2次的單詞和其出現的頻率。

(複習)委托 1、委托是可以指向方法的類型,調用委托變數時執行的就是變數指向的方法。舉例。 2、.NET中定義了泛型委托Action(無返回值)和Func(有返回值),所以一般不用自定義委托類型。舉例。

 static void Main(string[] args)
{
D1 d = F1;
d();
d = F2;
d();
D2 d2 = Add;
Console.WriteLine(d2(1,2));
Action a1 = F2;
a1();
Func<int, int, int> f = Add;
f(1,2);
Func<int, int, string> a = F33; //有返回值委托
a(1,2);
Action<int, string> c = F44; //無返回值委托
c(1,"zha");
}
static void F1()
{
Console.WriteLine("我是F1");
}
static void F2()
{
Console.WriteLine("我是F2");
}
static int Add(int a,int b)
{
return a + b;
}
static string F33(int i,int a)
{
return "hellow";
}
static void F44(int a,string b)
{

}

}
delegate void D1();
delegate int D2(int a,int b);

Lambda表達式

可以省略參數數據類型,因為編譯能根據委托類型推斷出參數的類型,用=>引出來方法體。

一步一步簡化

Action f1 = delegate ()
{
Console.WriteLine("我是方法");
};

Action f11 = () => Console.WriteLine("我是方法");

f1 (); //匿名方法無參無返回值
Action<string, int> f2 = (string a, int b) => Console.WriteLine($"a={a},b={b}"); ;
f2("zyb",1); //匿名方法 兩個參數
Func<int, int, int> f3 = (int a, int b) => { return a + b; };

f3(1,2); //有參有返回值 匿名方法
Func<int, int, int> f4 = (int i, int j) => i + j;
f4(1,2);

Func<int, int, int> f5 = ( i, j) =>
{
return i + j;
};
f5(1, 2);
Action<int> a1 = i => Console.WriteLine(i);
Func<int, bool> f66 = delegate (int i)
{
return i > 0;
};
Func<int, bool> f67 = i => i > 0;
Func<int, bool> f68 = delegate (int i)
{
return i > 5;
};
}

LING方法的背後

LING中提供了很多集合的擴展方法 配合lambda能簡化數據處理

 static void Main(string[] args)
{
int[] nums = new int[] { 20,55,51,55,58,99,22};
//where方法會遍歷集合中每個元素 對於每個元素
//都調用a=>a>10 這個表達式判斷一下是否為true
//如果為true 則把這個放到返回的集合中
//IEnumerable<int> result = nums.Where(a=>a>10);
var result = MyWhere2(nums,a => a > 10);
foreach (int item in result)
{
Console.WriteLine(item);
}
}

static IEnumerable<int> MyWhere(IEnumerable<int> items,Func<int,bool> f)
{
List<int> result = new List<int>();
foreach (int item in result)
{
if (f(item)==true)
{
result.Add(item);
}
}
return result;
}

static IEnumerable<int> MyWhere2(IEnumerable<int> items, Func<int, bool> f)
{
foreach (int item in items)
{
if (f(item) == true)
{
yield return item; //流水線處理 滿足條件直接返回
}
}
}
}

LING常用擴展方法 IEnumberble<T> 擴展方法

獲取一條數據(是否帶參數的兩種寫法):Single:有且只有一條滿足要求的數據;SingleOrDefault:最多只有一條滿足要求的數據; First :至少有一條,返回第一條; FirstOrDefault:返回第一條或者預設值; 選擇合適的方法,“防禦性編程”

LING解決面試

性能與面試 LINQ大部分時間不會影響性能,不過我曾經遇到過,講講。 面試時候的演算法題一般儘量避免使用正則表達式、LINQ等這些高級的類庫。大飯店面試大廚的故事。

案例1 有一個用逗號分隔的表示成績的字元串,如 "61,90,100,99,18,22,38,66,80,93,55,50,89",計算這些成績的平均值。

 string s = "33,55,66,99";
double avg2 = s.Split(',').Select(e => Convert.ToInt32(e)).Average();
Console.WriteLine(avg);

案例2 統計一個字元串中每個字母出現的頻率(忽略大小寫),然後按照從高到低的順序輸出出現頻率高於2次的單詞和其出現的頻率。

  string s = "fjdssl fjsdj ejejejej dfaSFSDd";
var item = s.Where(c => char.IsLetter(c)).Select(c => char.ToLower(c)) //過濾掉空格逗號
.GroupBy(c => c).Select(g => new { g.Key, Count = g.Count() })
.OrderByDescending(g => g.Count).Where(g => g.Count > 2);
foreach (var c in item)
{
Console.WriteLine(c);
}

依賴註入 控制反轉

概念 生活中的“控制反轉”:自己發電和用電網的電。 依賴註入(Dependency Injection,Dl)是控制反轉(lnversion of Control,IOC)思想的實現方式。 依賴註入簡化模塊的組裝過程,降低模塊之間的耦合度

自己發電的代碼
var connSettings =
ConfigurationManager.ConnectionStrings["connStr1"];
string connStr = connSettings.ConnectionString;SqIConnection conn = new
SqlConnection(connStr);缺點是?


//自己從配置文件取到連接字元串 然後實例一個連接資料庫的連接把字元串放進去

代碼控制反轉的目的 “怎樣創建XX對象"→“我要XX對象” 兩種實現方式: 1)服務定位器(ServiceLocator); 2)依賴註入(Dependency Injection,Dl);

DI幾個概念 服務(service):對象;註冊服務; 服務容器:負責管理註冊的服務;查詢服務:創建對象及關聯對象; 對象生命周期:Transient(瞬態);Scoped(範圍) ; Singleton(單例);

.NET中使用DI 2、根據類型來獲取和註冊服務。 可以分別指定服務類型(service type) 和實現類 型(implementation type)。這兩者可能相同,也可能不同。服務類型可以是類,也可以是介面,建議面向介面編程,更靈活。 3、.NET控制反轉組件取名為Dependencylnjection,但它包含ServiceLocator的功能。

生命周期

生命周期 1、給類構造函數中列印,看看不同生命周期的對象創建,使用serviceProvider.CreateScope()創建Scope。 2、如果一個類實現了IDisposable介面,則離開作用域之後容器會自動調用對象的Dispose方法。 3、不要在長生命周期的對象中引用比它短的生命周期的對象。在ASP.NET Core中,這樣做預設會拋異常。 4、生命周期的選擇:如果類無狀態,建議為Singleton;如果類有狀態,且有Scope控制,建議為Scoped,因為通常這種Scope控制下的代碼都是運行在同一個線程中的,沒有併發修改的問題;在使用Transient的時候要謹慎。 5、.NET註冊服務的重載方法很多,看著文檔琢磨吧。

//使用ioc容器
ServiceCollection services = new ServiceCollection();
services.AddTransient<TestSrvicelmpl>(); // 調用一次實例新的對象 瞬態
//services.AddSingleton<TestSrvicelmpl>(); //相同的對象 單例
//services.AddScoped<TestSrvicelmpl>(); //在範圍內拿到的是同一個對象
using (ServiceProvider sp = services.BuildServiceProvider()) //ServiceProvider相當於服務定位器
{
//TestSrvicelmpl T = sp.GetService<TestSrvicelmpl>();
//T.Name = "ZHAGNSNA";
//T.SayHi();

//TestSrvicelmpl T1 = sp.GetService<TestSrvicelmpl>();
//T1.Name = "放假啊可大幅度";
//T1.SayHi();
////比較兩個是否同一個對象 結果false
//Console.WriteLine(object.ReferenceEquals(T, T1));
//T.SayHi();
using (IServiceScope scope1 = sp.CreateScope())
{
TestSrvicelmpl T = scope1.ServiceProvider.GetService<TestSrvicelmpl>();
T.Name = "ZHAGNSNA";
T.SayHi();
TestSrvicelmpl T1 = scope1.ServiceProvider.GetService<TestSrvicelmpl>();
Console.WriteLine(object.ReferenceEquals(T, T1));
}

using (IServiceScope scope2 = sp.CreateScope())
{
TestSrvicelmpl T = scope2.ServiceProvider.GetService<TestSrvicelmpl>();
T.Name = "ZHAGNSNA";
T.SayHi();
TestSrvicelmpl T1 = scope2.ServiceProvider.GetService<TestSrvicelmpl>();
Console.WriteLine(object.ReferenceEquals(T, T1));
}
}

 

IServiceProvider的服務定位器方法:

T GetService<T>()如果獲取不到對象,則返回null。object GetService(Type serviceType) T GetRequiredService<T>()如果獲取不到對象,則拋異常 object GetRequiredService(Type serviceType) lEnumerable<T> GetServices<T>()適用於可能有很多滿足條件的服務 lEnumerable<object> GetServices(Type serviceType)

 ServiceCollection services = new ServiceCollection();
services.AddScoped<ITestServie, TestSrvicelmpl>();
services.AddScoped<ITestServie, TestSrvicelmpl2>();
services.AddSingleton(typeof(ITestServie),new TestSrvicelmpl());
using (ServiceProvider sp = services.BuildServiceProvider())
{
//GetService找不到服務返回null
//ITestServie ts1 = sp.GetService<ITestServie>();
//ts1.Name = "tom";
//ts1.SayHi();
//Console.WriteLine(ts1.GetType());

//GetRequiredService 必須的如果找不到 直接拋異常
//ITestServie ts1 = sp.GetRequiredService<ITestServie>();
//ts1.Name = "tom";
//ts1.SayHi();
//Console.WriteLine(ts1.GetType());

//註冊多個服務
//IEnumerable<ITestServie> tets = sp.GetServices<ITestServie>();
// foreach (ITestServie item in tets)
// {
// Console.WriteLine(item.GetType());
// }

ITestServie test1 = sp.GetService<ITestServie>();
Console.WriteLine(test1.GetType());


}

DI魅力漸顯:依賴註入

1、依賴註入是有傳染性”的,如果一個類的對象是通過DI創建的,那麼這個奚的構造函數中聲明的所有服務類型的參數都會被DI賦值;但是如果一個對象是程式員手動創建的,那麼這個對象就和DI沒有關係,它的構造函數中聲明的服務類型參數就不會被自動賦值。 2、.NET的DI預設是構造函數註入。 3、舉例:編寫一個類,連接資料庫做插入操作,並且記錄日誌(模擬的輸出),把Dao、日誌都放入單獨的服務類。connstr見備註。

static void Main(string[] args)
{
//降低模塊之間的耦合
ServiceCollection services = new ServiceCollection();
services.AddScoped<Controller>();
services.AddScoped<ILog,LogImp1>();
services.AddScoped<IStorage,StorageImp1>();
services.AddScoped<IConfig,ConfiImp1>();
using (var sp = services.BuildServiceProvider())
{
var c = sp.GetService<Controller>();
c.Test();
}
Console.ReadKey();
}

class Controller
{
private readonly ILog log;
private readonly IStorage storage;
public Controller(ILog log, IStorage storage)
{
this.log = log;
this.storage = storage;
}
public void Test()
{
log.Log("開始上傳");
storage.Save("fddfs","1.txt");
log.Log("上傳完畢");

}
}

interface ILog
{
public void Log(string msg);
}

public class LogImp1 : ILog
{
public void Log(string msg)
{
Console.WriteLine($"日誌:{msg}");
}
}

interface IConfig
{
public string GetValue(string name);
}

class ConfiImp1 : IConfig
{
public string GetValue(string name)
{
return "config";
}
}

interface IStorage
{
public void Save(string content,string name);
}

class StorageImp1 : IStorage
{
private readonly IConfig config;
public StorageImp1(IConfig config)
{
this.config = config;
}

public void Save(string content, string name)
{
string server = config.GetValue("server");
Console.WriteLine($"向伺服器{server}的文件名為{name}上傳{content}");
}
}
 
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 狀態機簡介: 狀態機是有限狀態自動機的簡稱,是現實事物運行規則抽象而成的一個數學模型。【規則的抽象】 有限狀態機一般都有以下特點: (1)可以用狀態來描述事物,並且任一時刻,事物總是處於一種狀態; (2)事物擁有的狀態總數是有限的; (3)通過觸發事物的某些行為,可以導致事物從一種狀態過渡到另一種狀 ...
  • 我前面使用的jdbc和jdbc的工具類集成的但是它們在少部分代碼的情況下會會簡單,但是以後如果項目較大jdbc的固定代碼會很難維護,如果使用框架會簡單很多,也標志著java學習正式進入到框架階段 ...
  • Hi, 我是Mic。 今天分享一道一線互聯網公司必問的面試題。 ”JVM如何判斷一個對象可以被回收“ 關於這個問題,來看看普通人和高手的回答。 普通人: 嗯。。。。。。。。。。 高手: 好的,面試官。 在JVM裡面,要判斷一個對象是否可以被回收,最重要的是判斷這個對象是否還在被使用,只有沒被使用的對 ...
  • 前言 今天的這個腳本,是一個別人發的外包,交互界面的代碼就不在這裡說了,但是可以分享下自動評論、自動點贊、自動關註、採集評論和視頻的數據是如何實現的 開發環境 python 3.8 運行代碼pycharm 2021.2 輔助敲代碼requests 第三方模塊 原理: 模擬客戶端,向伺服器發送請求 對 ...
  • 案例標題:用python可視化分析,B站Top100排行榜數據。 分析流程: 一、數據讀取 二、數據概覽 三、數據清洗 四、可視化分析 ·相關性分析-散點圖(scatter) ·得分分佈-餅圖(pie) ·各指標分佈-箱形圖(boxplot) ·視頻作者分析-詞雲圖(wordcloud) ...
  • 0、前言 這篇博客是給認識的那幫新手搞的,剛進入IT行業的崽們 這個東西配置好了,也可以選擇弄成線上文檔,下一次安裝IDEA時,有一個import導入配置,然後就可以自己配置好了( 雖然方便,但不建議用 ) 另外:IDEA建議別漢化,一開始接觸不習慣,後續使用一段時間之後就很舒服了 jetBrain ...
  • 一、SpringMVC使用 1.工程創建 創建maven工程。 添加java、resources目錄。 引入Spring-webmvc 依賴。 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc< ...
  • 前後連續的電腦語句組合在一起並有名字可供調用稱之為函數,本章主要介紹如何在程式中定義和使用函數其中包括如何調用函數、使用參數、使用參數的*和**運算,返回數值。如果把電腦語句比為武術動作的話,那麼函數就可以比喻為功夫“套路”,本質上“降龍十八掌”就是包含了18個語句的函數,那麼“葵花寶典”呢? ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...