分類
發燒車訊

發展電動車 梅克爾盼德國2030年前設百萬充電站

摘錄自2019年11月3日中央通訊社德國報導

德國總理梅克爾4日將與本國汽車工業代表會商,討論如何加速發展低碳排的電池驅動交通工具。她3日透過影片表示,德國在2030年前應設置100萬座電動車充電站。

德國境內目前僅有約2萬座電動車公共充電站。梅克爾指出:「為達此(發展電動車)目的,我們想在2030年前設置100萬座充電站,而產業界將必須加入相關計畫。我們要談的就是這個。」

路透社報導,預定明天在總理府舉行的會議,將是為相關議題舉辦的第二場,涉及儘速採取行動,以期交通運輸產業為德國達成國家碳排減量目標做出貢獻。會議將聚焦於汽油和柴油的替代方案,其中包括氫燃料和電池,以及政府和業界如何分攤給予消費者的補助,以刺激相關產品買氣。

梅克爾表示,政府也將致力於保障就業機會。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

分類
發燒車訊

「寂靜的春天」預言實現了 研究發現新菸鹼類影響水生物和魚群

環境資訊中心綜合外電;姜唯 編譯;林大利 審校

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

分類
發燒車訊

無人駕駛電動車?傳蘋果正在研發車類產品

  據知情人士透露,蘋果公司早在一年前就成立了汽車研發團隊,目前該團隊共有 100 多名員工,正在研發一款代號為 Titan 的電動車,同時蘋果公司與汽車產業中無人駕駛方面的資深人士互動頻繁,研發方向很有可能是一款無人駕駛的電動車。   蘋果公司對於汽車類產品和服務的研發計劃不僅僅局限在軟體系統,而是以打造整車為目標。在研發方面蘋果並沒有與傳統汽車廠商建立太多聯繫,據知情人士透露蘋果正在與汽車零組件廠商諮詢,主要是電力和車聯網方面的公司,這些諮詢並沒有涉及合作的部分。   蘋果公司已經招募了不少汽車產業的資深人士,包括前 Benz 北美研發中心的總裁 Johann Jungwirth,他在 2014 年 9 月加入蘋果四,此前曾負責 Benz 的自動駕駛、用戶界面設計、產品風格設計等工作。     本文全文授權轉載自《科技新報》─〈〉

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

分類
發燒車訊

挖角鋰電池廠 A123 傳蘋果電動車將於 2020 年量產

過去幾個月來,蘋果打算進軍終極行動裝置──汽車的傳言甚囂塵上。最新消息更顯示,蘋果正在加緊鞭策研發團隊,希望能在 2020 年產出旗下第一輛電動車。無獨有偶,數小時前才剛洩漏的法院文件顯示,美國汽車鋰離子電池與電池系統廠商 A123 Systems Inc. 控訴蘋果挖角多名重要的工程師,或許蘋果開發電動車是真有其事。   彭博社 20 日引述未具名消息人士報導,蘋果最快 2020 年就會開始量產電動車。一般來說,有經驗的汽車業者想要研發一款全新汽車、通常得花上 5 至 7 年的時間,假如要從零開始、時間更得費上 10 年之久。蘋果設定了如此緊迫的量產時程,凸顯了該公司對汽車領域的強大企圖心。   相較之下,特斯拉(Tesla Motors Inc.)、通用汽車(General Motors Co.)這兩家汽車大廠,則都預定要在 2017 年發表一輛單次充電後可行駛超過 200 英里、售價低於 4 萬美元的電動車。   蘋果的汽車團隊過去幾個月加緊聘人、目前已有 200 人之譜,而最新延攬的員工大多是電池、機器人專才。不過,根據消息人士的說法,倘若汽車的進展不如預期,蘋果仍可能推延開發案、或甚至直接抽手退出。

本站聲明:網站內容來源於EnergyTrend https://www.energytrend.com.tw/ev/,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

分類
發燒車訊

使用 nuget server 的 API 來實現搜索安裝 nuget 包

使用 nuget server 的 API 來實現搜索安裝 nuget 包

Intro

nuget 現在幾乎是 dotnet 開發不可缺少的一部分了,還沒有用過 nuget 的就有點落後時代了,還不快用起來

nuget 是 dotnet 里的包管理機制,類似於前端的 npm ,php 的 composer,java 里的 maven …

nuget 定義了一套關於 nuget server 的規範,使得用戶可以自己實現一個 nuget server

也正是這些規範,使得我們可以根據這些規範來實現 nuget server 的包管理的功能,今天主要介紹一下,根據 nuget server 的 api 規範使用原始的 HTTP 請求來實現 nuget 包的搜索和使用 nuget 提供的客戶端 SDK 來實現 nuget 包的搜索和下載

Nuget Server Api

Nuget 協議介紹

nuget 的協議有好幾個版本,目前主要用的是 v3,開源的 nuget server Baget 也實現了基於 nuget protocal v3 的規範

我們添加 nuget 源的時候會指定一個 source url,類似 https://api.nuget.org/v3/index.json 這樣的,着通常被稱為 Service Index,是一個 nuget 源的入口,有點類似於 Identity Server 里的發現文檔,通過這個地址可以獲取到一系列的資源的地址

有一些資源是協議規範里定義的必須要實現的,有一些是可選的,具體參考官方文檔,以後隨着版本變化,可能會有差異,目前 nuget.org 提供的資源如下:

Nuget.org 提供了兩種搜索的方式,

一個是 SearchQuery,會根據包名稱、 tag、description 等信息去匹配關鍵詞,

一個是 SearchAutocomplete 根據包名稱的前綴去匹配包的名稱

獲取某個 nuget 包的版本信息,可以使用 PackageBaseAddress 來獲取

ServiceIndex 返回的信息示例如下:

返回的信息會有一個 resources 的數組,會包含各種不同類型的資源,對應的 @id 就是調用這種類型的API要用到的地址,下面來看一個搜索的示例

在每個 API 的文檔頁面可以看到會使用的 @type,調用這個 API 的時候應該使用這些 @type 對應的資源

這裏的 @id 就是上面的 resource 對應的 @id

參數說明:

q 搜索時所用的關鍵詞,

skip/take 用來分頁显示查詢結果,

prelease 用來指定是否限制預覽版的 package,true 包含預覽版的 nuget 包,false 只包含已經正式發布的 nuget 包

semVerLevel 是用來指定包的語義版本

The semVerLevel query parameter is used to opt-in to SemVer 2.0.0 packages. If this query parameter is excluded, only packages with SemVer 1.0.0 compatible versions will be returned (with the standard NuGet versioning caveats, such as version strings with 4 integer pieces). If semVerLevel=2.0.0 is provided, both SemVer 1.0.0 and SemVer 2.0.0 compatible packages will be returned. See the SemVer 2.0.0 support for nuget.org for more information

packageType 用來指定 nuget 包的類型,目前支持的類型包括 Dependency(默認)項目依賴項,DotnetTool(dotnetcore 2.1 引入的 dotnet cli tool),Template (dotnet new 用) 自定義的項目模板

其他的 API 可以自行參考官方文檔:https://docs.microsoft.com/en-us/nuget/api/service-index

Packages

SearchQuery 返回的信息比較多而且可能並不準確,適用於不清楚包的名稱的時候使用,如果知道 nuget 包的名稱(PackageId) ,可以使用 SearchAutocomplete 來搜索,這樣更精準,返回的信息也更簡單,只有匹配的 package 名稱

通過原始 api 調用的方式實現 nuget 包的搜索

using var httpClient = new HttpClient(new NoProxyHttpClientHandler());
// loadServiceIndex
var serviceIndexResponse = await httpClient.GetStringAsync(NugetServiceIndex);
var serviceIndexObject = JObject.Parse(serviceIndexResponse);

var keyword = "weihanli";

//https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource
var queryEndpoint = serviceIndexObject["resources"]
    .First(x => x["@type"].Value<string>() == "SearchQueryService")["@id"]
    .Value<string>();
var queryUrl = $"{queryEndpoint}?q={keyword}&skip=0&take=5&prerelease=false&semVerLevel=2.0.0";
var queryResponse = await httpClient.GetStringAsync(queryUrl);
Console.WriteLine($"formatted queryResponse:");
Console.WriteLine($"{JObject.Parse(queryResponse).ToString(Formatting.Indented)}");

// https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource
var autoCompleteQueryEndpoint = serviceIndexObject["resources"]
    .First(x => x["@type"].Value<string>() == "SearchAutocompleteService")["@id"]
    .Value<string>();
var autoCompleteQueryUrl = $"{autoCompleteQueryEndpoint}?q={keyword}&skip=0&take=5&prerelease=false&semVerLevel=2.0.0";
var autoCompleteQueryResponse = await httpClient.GetStringAsync(autoCompleteQueryUrl);
Console.WriteLine($"formatted autoCompleteQueryResponse:");
Console.WriteLine($"{JObject.Parse(autoCompleteQueryResponse).ToString(Formatting.Indented)}");

output 示例:

Query 返回示例

Autocomplete 返回結果

從上面我們可以看到 Query 接口返回了很多的信息,Autocomplete 接口只返回了 package 的名稱,返回的信息更為簡潔,所以如果可以使用 Autocomplete 的方式就盡可能使用 Autocomplete 的方式

Package Versions

前面我們提到了可以使用 PackageBaseAddress 來查詢某個 nuget 包的版本信息,文檔地址:https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource,來看一下示例:

using (var httpClient = new HttpClient(new NoProxyHttpClientHandler()))
{
    // loadServiceIndex
    var serviceIndexResponse = await httpClient.GetStringAsync(NugetServiceIndex);
    var serviceIndexObject = JObject.Parse(serviceIndexResponse);

    // https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource
    var packageVersionsEndpoint = serviceIndexObject["resources"]
        .First(x => x["@type"].Value<string>() == "PackageBaseAddress/3.0.0")["@id"]
        .Value<string>();

    var packageVersionsQueryUrl = $"{packageVersionsEndpoint}/dbtool.core/index.json";
    var packageVersionsQueryResponse = await httpClient.GetStringAsync(packageVersionsQueryUrl);
    Console.WriteLine("DbTool.Core versions:");
    Console.WriteLine(JObject.Parse(packageVersionsQueryResponse)
                      .ToString(Formatting.Indented));
}

output 示例:

注:api 地址中的 packageId 要轉小寫

Nuget Client SDK

除了上面的根據 api 自己調用,我們還可以使用 nuget 提供的客戶端 sdk 實現上述功能,這裏就不詳細介紹了,有需要可能查閱官方文檔:https://docs.microsoft.com/en-us/nuget/reference/nuget-client-sdk

下面給出一個使用示例:

var packageId = "WeihanLi.Common";
var packageVersion = new NuGetVersion("1.0.38");

var logger = NullLogger.Instance;
var cache = new SourceCacheContext();
// 在 SDK 的概念里,每一個 nuget 源是一個 repository
var repository = Repository.Factory.GetCoreV3("https://api.nuget.org/v3/index.json");

// SearchQuery
{
    var resource = await repository.GetResourceAsync<PackageSearchResource>();
    var searchFilter = new SearchFilter(includePrerelease: false);

    var results = await resource.SearchAsync(
        "weihanli",
        searchFilter,
        skip: 0,
        take: 20,
        logger,
        CancellationToken.None);
    foreach (var result in results)
    {
        Console.WriteLine($"Found package {result.Identity.Id} {result.Identity.Version}");
    }
}
// SearchAutoComplete
{
    var autoCompleteResource = await repository.GetResourceAsync<AutoCompleteResource>();
    var packages =
        await autoCompleteResource.IdStartsWith("WeihanLi", false, logger, CancellationToken.None);
    foreach (var package in packages)
    {
        Console.WriteLine($"Found Package {package}");
    }
}
//
{
    // get package versions
    var findPackageByIdResource = await repository.GetResourceAsync<FindPackageByIdResource>();
    var versions = await findPackageByIdResource.GetAllVersionsAsync(
        packageId,
        cache,
        logger,
        CancellationToken.None);

    foreach (var version in versions)
    {
        Console.WriteLine($"Found version {version}");
    }
}

More

你可以使用 nuget sdk 方便的實現 nuget 包的下載安裝,內部實現了簽名校驗等,這樣就可以把本地不存在的 nuget 包下載到本地了,

實現示例:

{
    var pkgDownloadContext = new PackageDownloadContext(cache);
    var downloadRes = await repository.GetResourceAsync<DownloadResource>();

    var downloadResult = await RetryHelper.TryInvokeAsync(async () =>
        await downloadRes.GetDownloadResourceResultAsync(
            new PackageIdentity(packageId, packageVersion),
            pkgDownloadContext,
            @"C:\Users\liweihan\.nuget\packages", // nuget globalPackagesFolder
            logger,
            CancellationToken.None), r => true);
    Console.WriteLine(downloadResult.Status.ToString());
}

最後提供一個解析 nuget globalPackagesFolder 的兩種思路:

一個是前面有篇文章介紹的,有個默認的配置文件,然後就是默認的配置,寫了一個解析的方法示例,支持 Windows/Linux/Mac:

{
    var packagesFolder = Environment.GetEnvironmentVariable("NUGET_PACKAGES");

    if (string.IsNullOrEmpty(packagesFolder))
    {
        // Nuget globalPackagesFolder resolve
        if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
        {
            var defaultConfigFilePath =
                $@"{Environment.GetEnvironmentVariable("APPDATA")}\NuGet\NuGet.Config";
            if (File.Exists(defaultConfigFilePath))
            {
                var doc = new XmlDocument();
                doc.Load(defaultConfigFilePath);
                var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                if (node != null)
                {
                    packagesFolder = node.Attributes["value"]?.Value;
                }
            }

            if (string.IsNullOrEmpty(packagesFolder))
            {
                packagesFolder = $@"{Environment.GetEnvironmentVariable("USERPROFILE")}\.nuget\packages";
            }
        }
        else
        {
            var defaultConfigFilePath =
                $@"{Environment.GetEnvironmentVariable("HOME")}/.config/NuGet/NuGet.Config";
            if (File.Exists(defaultConfigFilePath))
            {
                var doc = new XmlDocument();
                doc.Load(defaultConfigFilePath);
                var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                if (node != null)
                {
                    packagesFolder = node.Attributes["value"]?.Value;
                }
            }

            if (string.IsNullOrEmpty(packagesFolder))
            {
                defaultConfigFilePath = $@"{Environment.GetEnvironmentVariable("HOME")}/.nuget/NuGet/NuGet.Config";
                if (File.Exists(defaultConfigFilePath))
                {
                    var doc = new XmlDocument();
                    doc.Load(defaultConfigFilePath);
                    var node = doc.SelectSingleNode("/configuration/config/add[@key='globalPackagesFolder']");
                    if (node != null)
                    {
                        packagesFolder = node.Value;
                    }
                }
            }

            if (string.IsNullOrEmpty(packagesFolder))
            {
                packagesFolder = $@"{Environment.GetEnvironmentVariable("HOME")}/.nuget/packages";
            }
        }
    }

    Console.WriteLine($"globalPackagesFolder: {packagesFolder}");
}

另一個是可以根據 nuget 提供的一個命令查詢 nuget locals global-packages -l,通過命令輸出獲取

Reference

  • https://github.com/WeihanLi/SamplesInPractice/blob/master/NugetSample/RawApiSample.cs
  • https://github.com/WeihanLi/SamplesInPractice/blob/master/NugetSample/NugetClientSdkSample.cs
  • https://docs.microsoft.com/en-us/nuget/reference/nuget-client-sdk
  • https://docs.microsoft.com/en-us/nuget/create-packages/set-package-type
  • https://docs.microsoft.com/en-us/nuget/api/overview
  • https://docs.microsoft.com/en-us/nuget/api/search-autocomplete-service-resource

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

分類
發燒車訊

C# 9.0 終於來了, Top-level programs 和 Partial Methods 兩大新特性探究

一:背景

1. 講故事

.NET 5 終於在 6月25日 發布了第六個預覽版,隨之而來的是更多的新特性加入到了 C# 9 Preview 中,這個系列也可以繼續往下寫了,廢話不多說,今天來看一下 Top-level programsExtending Partial Methods 兩大新特性。

2. 安裝必備

下載最新的 .net 5 preview 6

下載最新的 Visual Studio 2019 version 16.7 Preview 3.1

二:新特性研究

1. Top-level programs

如果大家玩過 python,應該知道在 xxx.py 中寫一句 print,這程序就能跑起來了,簡單高效又粗暴,很開心的是這特性被帶到了C# 9.0 中。

  • 修改前

using System;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Hello World!");
        }
    }

  • 修改后

System.Console.WriteLine("Hello World!");

這就有意思了,Main入口函數去哪了? 沒它的話,JIT還怎麼編譯代碼呢? 想知道答案的話用 ILSpy 反編譯看一下就好啦!


.class private auto ansi abstract sealed beforefieldinit $Program
	extends [System.Runtime]System.Object
{
	.custom instance void [System.Runtime]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
		01 00 00 00
	)
	// Methods
	.method private hidebysig static 
		void $Main (
			string[] args
		) cil managed 
	{
		// Method begins at RVA 0x2050
		// Code size 18 (0x12)
		.maxstack 8
		.entrypoint

		IL_0000: ldstr "Hello World!"
		IL_0005: call void [System.Console]System.Console::WriteLine(string)
		IL_000a: nop
		IL_000b: call string [System.Console]System.Console::ReadLine()
		IL_0010: pop
		IL_0011: ret
	} // end of method $Program::$Main

} // end of class $Program


從 IL 上看,類變成了 $Program, 入口方法變成了 $Main, 這就好玩了,在我們的印象中入口函數必須是 Main,否則編譯器會給你一個大大的錯誤,你加了一個 $ 符號,那CLR還能認識嗎? 能不能認識我們用 windbg 看一些託管和非託管堆棧,看看有什麼新發現。


0:010> ~0s
ntdll!NtReadFile+0x14:
00007ffe`f8f8aa64 c3              ret
0:000> !dumpstack
OS Thread Id: 0x7278 (0)
Current frame: ntdll!NtReadFile + 0x14
Child-SP         RetAddr          Caller, Callee
0000008551F7E810 00007ffed1e841dc (MethodDesc 00007ffe4020d500 + 0x1c System.Console.ReadLine()), calling 00007ffe400ab090
0000008551F7E840 00007ffe4014244a (MethodDesc 00007ffe401e58f0 + 0x3a $Program.$Main(System.String[])), calling 00007ffe40240f58
0000008551F7E880 00007ffe9fcc8b43 coreclr!CallDescrWorkerInternal + 0x83 [F:\workspace\_work\1\s\src\coreclr\src\vm\amd64\CallDescrWorkerAMD64.asm:101]
0000008551F7E8C0 00007ffe9fbd1e03 coreclr!MethodDescCallSite::CallTargetWorker + 0x263 [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:554], calling coreclr!CallDescrWorkerWithHandler [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:56]
0000008551F7E950 00007ffe9fb8c4e5 coreclr!MethodDesc::IsVoid + 0x21 [F:\workspace\_work\1\s\src\coreclr\src\vm\method.cpp:1098], calling coreclr!MetaSig::IsReturnTypeVoid [F:\workspace\_work\1\s\src\coreclr\src\vm\siginfo.cpp:5189]
0000008551F7EA00 00007ffe9fb8c4bf coreclr!RunMainInternal + 0x11f [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1488], calling coreclr!MethodDescCallSite::CallTargetWorker [F:\workspace\_work\1\s\src\coreclr\src\vm\callhelpers.cpp:266]
0000008551F7EB30 00007ffe9fb8c30a coreclr!RunMain + 0xd2 [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1559], calling coreclr!RunMainInternal [F:\workspace\_work\1\s\src\coreclr\src\vm\assembly.cpp:1459]

從上面堆棧的流程圖看: coreclr!RunMain -> coreclr!MethodDesc -> coreclr!CallDescrWorkerInternal -> $Program.$Main, 確實被調用了,不過有一個重大發現,在 $Program.$Main 調用之前底層的 CLR 讀取了 方法描述符,這就是一個重大突破點,方法描述符在哪裡呢? 可以用 ildasm 去看一下元數據列表。

可以看到,入口函數那裡打上了一個 ENTRYPOINT 標記,這就說明入口函數名其實是可以隨便更改的,只要被 ENTRYPOINT打上標記即可,CoreCLR就能認的出來~~~

2. Partial Methods

我們知道 部分方法 是一個很好的樁函數,而且在 C# 3.0 中就已經實現了,那時候給我們增加了很多限制,如下圖:

翻譯過來就是:

  • 部分方法的簽名必須一致

  • 方法必須返回void

  • 不允許使用訪問修飾符,而且還是隱式私有的。

在 C# 9.0 中放開了對 方法簽名 的所有限制,正如 issue 總結:

這是一個非常好的消息,現在你的部分方法上可以加上各種類型的返回值啦,這裏我舉一個例子:


    class Program
    {
        static void Main(string[] args)
        {
            var person = new Person();

            Console.WriteLine(person.Run("jack"));
        }
    }

    public partial class Person
    {
        public partial string Run(string name);
    }

    public partial class Person
    {
        public partial string Run(string name) => $"{name}:開溜了~";
    }

然後我們用 ILSpy 簡單看看底層怎麼玩的,如下圖可以看到其實就是一個簡單的合成,對吧。

現在我有想法了,如果我不給 Run 方法實現會怎麼樣? 把下面的 partial 類註釋掉看一下。

從報錯信息看,可訪問的修飾符必須要有方法實現,還以為直接編譯的時候抹掉呢。 這就起不到樁函數的作用:-D,不過這個特性還是給了我們更多的可能用的到的應用場景吧。

三:總結

本篇兩個特性還是非常實用的,Top-level programs 讓我們可以寫更少的代碼,甚至拿起 記事本 都可以快捷的編寫類似一次性使用的測試代碼, Partial Methods 特性留給大家補充吧,我基本上算是沒用過 (┬_┬)。

如您有更多問題與我互動,掃描下方進來吧~

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

分類
發燒車訊

台灣團隊以《海洋危機》出席全球最大桌遊展

摘錄自2019年11月4日自由時報報導

全球最大桌上遊戲大會「德國埃森桌遊展(SPIEL)」上月下旬開展時,台灣業者獨闖,靠實力獲邀參與官方論壇主講「環境友善」議題,直接正名Taiwan登上官網與活動介紹,不是以China(中國)或Chinese Taipei(中華台北)名稱參與,更透過桌遊,將台灣文化輸出全世界。

獨立遊戲出版業者「綿羊犬百寶箱」公司負責人林啟維表示,SPIEL桌遊展是全球最大,展期是上月24至27日,今年便8月收到該展邀請,希望出席大會在上月26日舉辦的官方論壇活動,主講「環境友善」議題,便將今年開發的《海洋危機》獲台灣逾600間學校使用的經驗,到場分享。

林啟維說,論壇中看見德國遊戲市場與亞洲新興市場的差異,永續話題也在當場彼此交鋒,但結束後卻有不少德國、荷蘭等地學校老師、環境工作者現身,指定購買台灣桌遊,另外過去也開發台灣內容的《史前歷險紀》,不少外國人玩完才發現是台灣史前文化,同樣把台灣文化輸出海外。

林啟維認為,「用熱情、專業將自己手邊的事情做好,當機會來臨,我們就會被看見。」而桌遊設計領域,一直由自由派的創作者們領導著,而台灣在遊戲設計與市場成熟度,也大大領先中國,因此這次論壇無任何政治干預,讓自已不僅代表台灣,也更代表東亞桌遊開發與應用的精神,未來將繼續努力,持續在國際舞台綻放。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

分類
發燒車訊

習近平馬克宏聯合聲明 強調巴黎氣候協定不可逆

摘錄自2019年11月6日中央社外電報導

美國本週向聯合國提交退出巴黎氣候協定的通知信函後,中國國家主席習近平和法國總統馬克宏(Emmanuel Macron)今天(6日)共同宣布,堅定支持巴黎氣候協定並強調協定「不可逆」。

法新社報導,儘管有越來越多證據顯示氣候變遷的事實和影響,美國總統川普仍執意退出巴黎氣候協定,世界各國紛紛表達遺憾及關切。

華府4日向聯合國(UN)提交退出巴黎氣候協定(Paris Agreement)的通知信函,讓世界最大經濟體美國成為至今唯一退出這項協定的國家。

根據美國前總統歐巴馬(Barack Obama)談成的這項氣候協定,11月4日是美方最早可以正式提出退出協定的首日。

習近平和馬克宏在北京舉行會談後的聯合聲明說,中法兩國領導人重申「他們堅定支持巴黎氣候協定,他們認為這項協定是不可逆轉的進程,也是針對氣候問題採取強而有力行動時的方針」。

兩人在北京會談後,馬克宏坐在習近平旁邊。當時馬克宏沒有直接指名美國,只說他「對於其他人所做的選擇深感遺憾」。

本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準

分類
發燒車訊

HTML&CSS面試高頻考點(二)

HTML&CSS面試高頻考點(一)    

6. W3C盒模型與怪異盒模型

  • 標準盒模型(W3C標準)
  • 怪異盒模型(IE標準)

怪異盒模型下盒子的大小=width(content + border + padding) + margin,即真實大小

*參考標準模式與兼容模式的區別,兼容模式下為怪異盒模型。

*注意box-sizing可以改變盒模型(box-sizing:border-box即為怪異盒模型)。

7. 水平垂直居中的方法

(1)定寬居中

1. absolute + 負margin

//父元素
position: relative;
//子元素
position: absolute;
top: 50%;
left: 50%;
//margin設置自身一半的距離
margin-top: -50px;
margin-left: -50px;

2. absolute + margin: auto

//父元素
position: relative;
//子元素
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;

 3. absolute + calc

//父元素
position: relative;
//子元素
position: absolute;
//減去自身一半的寬高
top: calc(50% - 50px);
left: calc(50% - 50px);

 *calc() 函數用於動態計算長度值。

 4. min-height: 100vh + flex + margin:auto

main{   min-height: 100vh;
   /* vh相對於視窗的高度,視窗高度是100vh */
  /* “視區”所指為瀏覽器內部的可視區域大小,   不包含任務欄標題欄以及底部工具欄的瀏覽器區域大小。 */   display: flex;
} div{   margin: auto;
}

(2)不定寬居中

1. absolute + transform

//父元素
position: relative;
//子元素
position: absolute;
top:50%;
left:50%;
transform:translate(-50%,-50%);

2. line-height

//父元素 .wp { text-align: center; line-height: 300px;
}
//子元素
.box { display: inline-block; vertical-align: middle; line-height: inherit; text-align: left; }

3. flex布局

display: flex;//flex布局
justify-content: center;//使子項目水平居中
align-items: center;//使子項目垂直居中

4. table-cell布局

因為table-cell相當與表格的td,無法設置寬和高,所以嵌套一層,嵌套一層必須設置display: inline-block

<div class="box">
    <div class="content">
        <div class="inner">
        </div>
    </div>
</div> .box { //只有這裏可以設置寬高 display: table; //這是嵌套的一層,會被table-cell覆蓋 } .content { display: table-cell; vertical-align: middle;//使子元素垂直居中 text-align: center;//使子元素水平居中 } .inner { display: inline-block; //子元素 }

8. BFC

 前文鏈接:點擊這裏

BFC:Block formatting context(塊級格式化上下文),是一個獨立的渲染區域,只有Block-level box參与,與外部區域毫不相干。

  • block-level box:display屬性為block, list-item, table的元素。
  • inline-level box:display屬性為inline, inline-box, inline-table的元素。

(1)BFC的布局規則

  • 內部box在垂直方向一個個放置;
  • 同一個BFC的兩個相鄰box的margin會發生重疊;
  • 每個盒子的margin左邊與包含塊的border左邊相接觸,即使存在浮動也是如此;
  • BFC區域不會和float box重疊;
  • 計算BFC高度時,浮動元素也參与計算。

(2)開啟BFC的方法

  • float的值不是none
  • position的值不是static或relative
  • display的值是inline-block, table-cell, flex, table-caption或inline-flex
  • overflow的值不是visible

(3)BFC的作用

1. 避免margin塌陷

根據BFC的布局規則2,我們可以通過設置兩個不同的BFC的方式解決margin塌陷的問題。

2. 自適應兩欄布局

根據BFC的布局規則3和4,我們將右側div開啟BFC就可以形成自適應兩欄布局。

.left { float: left; //左側浮動 }

.left { float: left;
} .right { overflow: hidden; //開啟BFC }

3. 清除浮動

當不給父節點設置高度的時候,如果子節點設置浮動,父節點會發生高度塌陷。這個時候就要清除浮動。

根據規則5,只需給父元素激活BFC就可以達到目的。

.par { overflow: hidden; //父元素開啟BFC } .child { float: left; //子元素浮動 }

9. 清除浮動

 這篇有寫:點這裏

10. position屬性

 這篇有寫:點這裏

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【【其他文章推薦】

※帶您來了解什麼是 USB CONNECTOR  ?

※自行創業缺乏曝光? 網頁設計幫您第一時間規劃公司的形象門面

※如何讓商品強力曝光呢? 網頁設計公司幫您建置最吸引人的網站,提高曝光率!

※綠能、環保無空污,成為電動車最新代名詞,目前市場使用率逐漸普及化

※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益

※教你寫出一流的銷售文案?

分類
發燒車訊

利用Tu Share獲取股票交易信息,c#實現

 一、什麼是Tu Share

Tushare是一個免費、開源的python財經數據接口包。主要實現對股票等金融數據從數據採集清洗加工 到 數據存儲的過程,用戶可以免費(部分數據的下載有積分限制)的通過它提供的財經接口獲取股票交易、期貨等財經信息,功能非常強大。該接口和直接到各財經網站爬數據相比,最大的優勢就是快,去傳統財經網站爬數據,好多關鍵性的股票信息只能一隻股一隻股爬,而Tu Share的API,一個調用可以獲得一天的全部數據,速度差了好幾個數量級。另外一方面各財經網站的接口的API沒有對外文檔化,隨時可能變化,而Tu Share的API有正式的文檔化相對比較穩定。

二、如何註冊

該網站使用積分制來控制數據的訪問權限,如果想要訪問數據,先要到下面這個網址完成註冊,https://tushare.pro/register。註冊完成后,可以需要到個人主頁中拷貝Token,這個Token會在以後的訪問中用到,步驟如下

1、登錄成功后,點擊右上角->個人主頁

2、 在“用戶中心”中點擊“接口TOKEN”

 

3、 可以點擊右側複製按鈕複製token

三、Http API說明

Tushare HTTP數據獲取的方式,採用了post的機制,通過提交JSON body參數,就可以獲得您想要的數據。具體參數說明如下:

輸入參數

api_name:接口名稱,比如stock_basic

token :用戶唯一標識,可通過登錄pro網站獲取

params:接口參數,如daily接口中start_date和end_date

fields:字段列表,用於接口獲取指定的字段,以逗號分隔,如”open,high,low,close”

輸出參數

code: 接口返回碼,2002表示權限問題。

msg:錯誤信息,比如“系統內部錯誤”,“沒有權限”等

data:數據,data里包含fields和items字段,分別為字段和數據內容

四、c#(.net core)實現

1、在Visual Studio中安裝下面幾個包:Microsoft.Extensions.Http、Newtonsoft.Json

2、封裝方法,實現對REST web service的調用

public interface IHttpClientUtility
{
     string HttpClientPost(string url, object datajson);
}
public class HttpClientUtility : IHttpClientUtility
    {
        

        public HttpClientUtility()
        {
            
        }
        public  string HttpClientPost(string url, object datajson)
        {
            using (HttpClient httpClient = new HttpClient()) //http對象
            {
                httpClient.DefaultRequestHeaders.Accept.Clear();
                httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
                httpClient.Timeout = new TimeSpan(0, 0, 5);
                //轉為鏈接需要的格式
                HttpContent httpContent = new JsonContent(datajson);
                //請求
                HttpResponseMessage response = httpClient.PostAsync(url, httpContent).Result;
                if (response.IsSuccessStatusCode)
                {
                    Task<string> t = response.Content.ReadAsStringAsync();
                    return t.Result;
                }
                throw new Exception("調用失敗");
            }
                                                                       
        }
    }

 

    public class JsonContent : StringContent
    {
        public JsonContent(object value)
            : base(JsonConvert.SerializeObject(value), Encoding.UTF8,
                "application/json")
        {
        }

        public JsonContent(object value, string mediaType)
            : base(JsonConvert.SerializeObject(value), Encoding.UTF8, mediaType)
        {
        }
    }

3、封裝對Tu Share API的調用

public  class TuShareUtility 
    {
        private IHttpClientUtility _httpClientUtility;
        private string _url = "http://api.waditu.com/";
        
        public TuShareUtility(IHttpClientUtility httpClientUtility)
        {
            _httpClientUtility = httpClientUtility;
        }

        /// <summary>
        /// 調用TuShare API
        /// </summary>
        /// <param name="apiName"></param>
        /// <param name="parmaMap"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        public  DataTable GetData(string apiName,Dictionary<string,string> parmaMap,params string[] fields)
        {
            var tuShareParamObj=new TuShareParamObj(){ ApiName = apiName ,Params = parmaMap,Fields = string.Join(",",fields)};
            //做Http調用
            var result=_httpClientUtility.HttpClientPost(_url, tuShareParamObj);
            //將返回結果序列化成對象
            var desResult=JsonConvert.DeserializeObject<TuShareResult>(result);
            //如果調用失敗,拋出異常
            if(!string.IsNullOrEmpty(desResult.Msg))
                throw new Exception(desResult.Msg);
            //返回結果分成兩部分,一部分是列頭信息,另一部分是數據本身,用這兩部分數據可以構建DataTable
            DataTable dt = new DataTable();
            foreach (var dataField in desResult.Data.Fields)
            {
                dt.Columns.Add(dataField);
            }

            foreach (var dataItemRow in desResult.Data.Items)
            {
                var newdr=dt.NewRow();
                for (int i=0;i< dataItemRow.Length;i++)
                {
                    newdr[i] = dataItemRow[i];
                }

                dt.Rows.Add(newdr);
            }
            return dt;
        }

        private class TuShareParamObj
        {
            [JsonProperty("api_name")]
            public string ApiName { get; set; }

            [JsonProperty("token")]
            public string Token { get; } = "****************";//你的Token

            [JsonProperty("params")]
            public Dictionary<string, string> Params { get; set; }

            [JsonProperty("fields")]
            public string Fields { get; set; }
        }

        private class TuShareData
        {
            [JsonProperty("fields")]
            public string[] Fields { get; set; }

            [JsonProperty("items")]
            public string[][] Items { get; set; }
        }

        private class TuShareResult
        {
            [JsonProperty("code")]
            public string Code { get; set; }

            [JsonProperty("msg")]
            public string Msg { get; set; }

            [JsonProperty("data")]
            public TuShareData Data { get; set; }
        }
    }

4、調用示例

獲得日線行情,整個過程1秒左右,返回6月24日,股票相關交易信息,代碼如下,(該網站的其它接口定義可以到https://tushare.pro/document/2查看)

var tuShareUtility=new TuShareUtility();
Dictionary<string, string> p = new Dictionary<string, string>();
p["trade_date"] = "20200624";
var table = tuShareUtility.GetData("daily", p, "");

返回如下結果

返回字段說明

名稱 類型 描述
ts_code str 股票代碼
trade_date str 交易日期
open float 開盤價
high float 最高價
low float 最低價
close float 收盤價
pre_close float 昨收價
change float 漲跌額
pct_chg float 漲跌幅 (未復權,如果是復權請用 通用行情接口 )
vol float 成交量 (手)
amount float 成交額 (千元)

 

 

 

  本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】

USB CONNECTOR掌控什麼技術要點? 帶您認識其相關發展及效能

台北網頁設計公司這麼多該如何選擇?

※智慧手機時代的來臨,RWD網頁設計為架站首選

※評比南投搬家公司費用收費行情懶人包大公開

※幫你省時又省力,新北清潔一流服務好口碑

※回頭車貨運收費標準