ความหมายของแอปพลิเคชันของไลบรารีมาตรฐานขึ้นอยู่กับ metapackage คืออะไร?


100

สมมติว่าฉันมีไลบรารีคลาสที่ฉันต้องการกำหนดเป้าหมาย netstandard1.3 แต่ก็ใช้BigIntegerด้วย นี่คือตัวอย่างเล็กน้อย - ซอร์สไฟล์เดียวคือAdder.cs:

using System;
using System.Numerics;

namespace Calculator
{
    public class Adder
    {
        public static BigInteger Add(int x, int y)
            => new BigInteger(x) + new BigInteger(y);            
    }
}

ย้อนกลับไปในโลกของproject.jsonฉันจะกำหนดเป้าหมายnetstandard1.3ในframeworksส่วนนี้และมีการพึ่งพาอย่างชัดเจนSystem.Runtime.Numericsเช่นเวอร์ชัน 4.0.1 แพ็คเกจ nuget ที่ฉันสร้างจะแสดงรายการการอ้างอิงนั้น

ในโลกใหม่ที่กล้าหาญของ csproj ตาม dotnet เครื่องมือ (ฉันใช้ v1.0.1 ของเครื่องมือบรรทัดคำสั่ง) มีความนัยอ้างอิงแพคเกจ metapackageไปเมื่อกำหนดเป้าหมายNETStandard.Library 1.6.1 netstandard1.3ซึ่งหมายความว่าไฟล์โครงการของฉันมีขนาดเล็กมากเพราะไม่ต้องการการพึ่งพาอย่างชัดเจน:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
  </PropertyGroup>
</Project>

... แต่แพคเกจนักเก็ตที่ผลิตขึ้นนั้นมีการพึ่งพาNETStandard.Libraryซึ่งแสดงให้เห็นว่าในการใช้ห้องสมุดขนาดเล็กของฉันคุณต้องมีทุกอย่างที่นั่น

ปรากฎว่าฉันสามารถปิดใช้งานฟังก์ชันนั้นโดยใช้DisableImplicitFrameworkReferencesจากนั้นเพิ่มการอ้างอิงด้วยตนเองอีกครั้ง:

<Project Sdk="Microsoft.NET.Sdk">    
  <PropertyGroup>
    <TargetFramework>netstandard1.3</TargetFramework>
    <DisableImplicitFrameworkReferences>true</DisableImplicitFrameworkReferences>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="System.Runtime.Numerics" Version="4.0.1" />
  </ItemGroup>    
</Project>

ตอนนี้แพ็คเกจ NuGet ของฉันบอกว่ามันขึ้นอยู่กับอะไร โดยสัญชาตญาณแล้วสิ่งนี้ให้ความรู้สึกเหมือนแพ็คเกจที่ "เพรียวบางกว่า"

แล้วความแตกต่างที่แท้จริงสำหรับผู้ใช้ห้องสมุดของฉันคืออะไร? หากมีคนพยายามใช้ในแอปพลิเคชัน UWP รูปแบบการอ้างอิงที่ "ถูกตัด" อย่างที่สองหมายความว่าแอปพลิเคชันที่ได้จะมีขนาดเล็กลงหรือไม่

โดยไม่ได้จัดทำเอกสารDisableImplicitFrameworkReferencesอย่างชัดเจน (เท่าที่ฉันเคยเห็นฉันอ่านเกี่ยวกับเรื่องนี้ในปัญหา ) และโดยการทำให้การพึ่งพาโดยนัยเป็นค่าเริ่มต้นเมื่อสร้างโครงการ Microsoft กำลังสนับสนุนให้ผู้ใช้พึ่งพา metapackage - แต่ฉันจะเป็นได้อย่างไร แน่ใจว่าไม่มีข้อเสียเมื่อฉันสร้างแพ็คเกจไลบรารีคลาส


3
มันควรจะตั้งข้อสังเกตว่าการพึ่งพาการตัดแต่งเป็นกำลังทำงานอยู่ ปัจจุบันขนาดของHello World!แอปพลิเคชันในตัวลดลงเหลือ <10MB
ABarney

@ABarney 10MB ยังคงมากเกินไปเมื่อเทียบกับขนาด< 20KBของโครงการ. NET Framework C # แบบคลาสสิก
Dai

คำตอบ:


76

ในอดีตที่ผ่านมาเราได้รับการพัฒนาข้อเสนอแนะที่จะไม่อ้างอิงแพคเกจเมตา ( NETStandard.Library) จากแพคเกจ NuGet แต่แทนที่จะอ้างอิงแต่ละแพคเกจเหมือนและSystem.Runtime System.Collectionsเหตุผลก็คือเราคิดว่าแพคเกจเมตาเป็นชวเลขสำหรับแพ็คเกจจำนวนมากที่เป็นหน่วยการสร้างอะตอมที่แท้จริงของแพลตฟอร์ม. NET สมมติฐานคือเราอาจลงเอยด้วยการสร้างแพลตฟอร์ม. NET อื่นที่รองรับบล็อกอะตอมเหล่านี้เพียงบางส่วน แต่ไม่ใช่ทั้งหมด ดังนั้นยิ่งคุณอ้างอิงแพ็คเกจน้อยเท่าไหร่คุณก็จะพกพาได้มากขึ้นเท่านั้น นอกจากนี้ยังมีข้อกังวลเกี่ยวกับการใช้เครื่องมือของเรากับกราฟแพ็คเกจขนาดใหญ่

ต่อไปเราจะทำให้สิ่งนี้ง่ายขึ้น:

  1. .NET มาตรฐานเป็นกลุ่มอาคารอะตอม กล่าวอีกนัยหนึ่งแพลตฟอร์มใหม่ไม่ได้รับอนุญาตให้ใช้ชุดย่อย. NET Standard - พวกเขาต้องใช้งานทั้งหมด

  2. เรากำลังจะเลิกใช้แพ็คเกจเพื่ออธิบายแพลตฟอร์มของเรารวมถึง. NET Standard

ซึ่งหมายความว่าคุณจะไม่ต้องอ้างอิงแพ็คเกจ NuGet สำหรับ. NET Standard อีกต่อไป คุณแสดงการพึ่งพาของคุณกับโฟลเดอร์ lib ซึ่งเป็นวิธีการทำงานของแพลตฟอร์ม. NET อื่น ๆ ทั้งหมดโดยเฉพาะ. NET Framework

NETStandard.Libraryอย่างไรก็ตามขณะนี้การขับรถของเราจะยังคงเผาไหม้ในการอ้างอิงถึง ไม่มีอันตรายใด ๆ ในสิ่งนั้นมันจะกลายเป็นเรื่องซ้ำซ้อนในการก้าวไปข้างหน้า

ฉันจะอัปเดตคำถามที่พบบ่อยใน repo. NET Standard เพื่อรวมคำถามนี้

อัพเดท : คำถามนี้ตอนนี้เป็นส่วนหนึ่งของคำถามที่พบบ่อย


9
ขอบคุณ - สิ่งนี้สมเหตุสมผลมาก ฉันคิดว่าฉันสับสนส่วนหนึ่งเพราะในโลก project.json ฉันต้องเพิ่มการอ้างอิงแม้ว่าแพ็คเกจจะเป็นส่วนหนึ่งของกรอบงานที่ฉันกำหนดเป้าหมายตามเหตุผล (เช่น System.Runtime.Numerics สำหรับ netstandard1.3) - ดังนั้นฉันจึงคิดว่า NETStandard.Library คือ ดึงพวกเขาเข้ามาเป็นแหล่งอ้างอิงจริงๆ
Jon Skeet

2
แย่จัง. ฉันชอบแนวคิดในการอ้างอิงแพ็คเกจเพราะรู้สึกว่าฉันสามารถอ้างอิงเฉพาะสิ่งที่ฉันต้องการแทนที่จะเป็น "อ่างล้างจาน" ทั้งหมด บางทีฉันคิดไม่ถูก?
Nate Barbettini

3
คุณไม่จำเป็นต้องคิดในทางที่ผิด แต่คำถามคือทำไมคุณถึงสนใจ สิ่งสำคัญคือต้องเข้าใจว่าแพลตฟอร์มนี้ไม่สามารถประกอบได้อย่างไม่มีที่สิ้นสุด เมื่อคุณรันในสภาพแวดล้อมเฟรมเวิร์กที่ใช้ร่วมกัน (.NET Framework, Mono, .NET Core) บิตเหล่านี้ทั้งหมดจะมีอยู่แล้ว หากคุณสร้างแอปในตัว (Xamarin, Mono / .NET Core with linker) เราสามารถตัดแต่งโดยอัตโนมัติตามการใช้งานจริงของคุณ ไม่ว่าจะด้วยวิธีใดคุณจะไม่สูญเสียอะไรไปเลยโดยการไม่อ้างอิงบล็อกเล็ก ๆ
Immo Landwerth

3
สิ่งที่เกี่ยวกับการให้คอมไพเลอร์บังคับใช้กฎเช่นการป้องกันไม่ให้นักพัฒนาส่งคำขอ http ในโครงการตรรกะทางธุรกิจโดยไม่อนุญาตให้แพคเกจนั้นเสียแรงเปล่า?
David Ferretti

ไม่จำเป็น แต่คุณจะบังคับใช้อย่างไรนั่นคือสิ่งที่ทำให้นักพัฒนาไม่สามารถเพิ่มข้อมูลอ้างอิงได้ ฉันจะเขียนตัววิเคราะห์ที่ถูกฉีดในเวลาสร้างเพื่อบังคับใช้กฎเลเยอร์และทำให้เกิดข้อผิดพลาดในเครื่องสร้าง
Immo Landwerth

19

ทีมงานเคยแนะนำให้คิดว่าชุดแพ็คเกจที่บางที่สุดคืออะไร พวกเขาไม่ทำเช่นนี้อีกต่อไปและแนะนำให้ผู้คนเพียงแค่นำ NETStandard.Library มาแทน (ในกรณีของโปรเจ็กต์สไตล์ SDK สิ่งนี้จะทำให้คุณโดยอัตโนมัติ)

ฉันไม่เคยได้รับคำตอบอย่างตรงไปตรงมาเลยว่าทำไมถึงเป็นเช่นนั้นดังนั้นให้ฉันเดาอย่างมีความรู้

สาเหตุหลักน่าจะมาจากการที่อนุญาตให้ซ่อนความแตกต่างในเวอร์ชันของไลบรารีที่พึ่งพาซึ่งคุณจะต้องติดตามตัวเองเมื่อเปลี่ยนกรอบเป้าหมาย นอกจากนี้ยังเป็นระบบที่เป็นมิตรกับผู้ใช้มากขึ้นด้วยไฟล์โครงการที่ใช้ SDK เนื่องจากคุณไม่ต้องการการอ้างอิงใด ๆ เพื่อให้ได้แพลตฟอร์มที่เหมาะสม (เช่นเดียวกับที่คุณใช้กับการอ้างอิงเริ่มต้นใน Desktop-land โดยเฉพาะ mscorlib ).

ด้วยการผลักดัน meta-definition ของความหมายของการเป็นnetstandardไลบรารีหรือnetcoreappแอปพลิเคชันลงในแพ็คเกจ NuGet ที่เหมาะสมพวกเขาไม่จำเป็นต้องสร้างความรู้พิเศษใด ๆ ในคำจำกัดความของสิ่งเหล่านั้นตามที่ Visual Studio (หรือdotnet new) เห็น

สามารถใช้การวิเคราะห์แบบคงที่ในระหว่างการเผยแพร่เพื่อ จำกัด DLL ที่จัดส่งซึ่งเป็นสิ่งที่พวกเขาทำในปัจจุบันเมื่อทำการรวบรวมแบบเนทีฟสำหรับ UWP (แม้ว่าจะมีข้อแม้บางประการ) พวกเขาไม่ได้ทำเช่นนั้นในวันนี้สำหรับ. NET Core แต่ฉันคิดว่าเป็นการเพิ่มประสิทธิภาพที่พวกเขาพิจารณา (เช่นเดียวกับการสนับสนุนโค้ดเนทีฟ)

ไม่มีอะไรหยุดคุณจากการเลือกมากถ้าคุณเลือก ฉันเชื่อว่าคุณจะพบว่าคุณเกือบจะเป็นคนเดียวที่ทำมันซึ่งก็เอาชนะจุดประสงค์ได้เช่นกัน (เพราะจะถือว่าทุกคนเข้ามาNETStandard.LibraryหรือMicrosoft.NETCore.App)


6
ผมเห็นด้วยแน่นอนมันขัดแย้งกับวัตถุประสงค์เมื่อมีมากกว่าหนึ่งพึ่งพาถ้าใด ๆ NETStandard.Libraryของพวกเขานำใน แน่นอนว่ามันค่อนข้างตอบสนองตัวเอง ... ถ้าฉันขึ้นอยู่กับNETStandard.LibraryNoda Time นั่นหมายความว่าห้องสมุดอื่น ๆ ที่สร้างขึ้นบน Noda Time ไม่มีเหตุผลที่จะตัดทอนการอ้างอิง ฯลฯ ตอนนี้มันน่าดึงดูดที่จะเลือก (เวลา Noda คือ มุ่งหน้าไปสู่ ​​2.0) จากนั้นผ่อนคลายเล็กน้อยในภายหลังเมื่อมีการจัดตั้งอนุสัญญาแล้ว - การเปลี่ยนจากการเลือกเป็นแบบ lib จะเป็นการเปลี่ยนแปลงที่ไม่ทำลายฉันถือว่า แต่สิ่งที่ตรงกันข้ามไม่เป็นความจริง
Jon Skeet

8

คุณไม่จำเป็นต้องปิดใช้งานการอ้างอิงโดยนัย แพลตฟอร์มทั้งหมดที่ไลบรารีจะสามารถทำงานได้จะมีแอสเซมบลีที่การNETStandard.Libraryอ้างอิงนั้นต้องการอยู่แล้ว

NET Standard Library เป็นข้อมูลจำเพาะชุดของแอสเซมบลีการอ้างอิงที่คุณรวบรวมโดยมีชุดของ API ที่รับประกันว่ามีอยู่ในชุดแพลตฟอร์มและเวอร์ชันของแพลตฟอร์มที่ทราบเช่น. NET Core หรือ. NET Framework . ไม่ใช่การนำแอสเซมบลีเหล่านี้ไปใช้ แต่มีรูปร่าง API เพียงพอที่จะอนุญาตให้คอมไพเลอร์สร้างโค้ดของคุณได้สำเร็จ

การนำไปใช้งานสำหรับ API เหล่านี้จัดเตรียมโดยแพลตฟอร์มเป้าหมายเช่น. NET Core, Mono หรือ. NET Framework พวกเขาจัดส่งด้วยแพลตฟอร์มเพราะเป็นส่วนสำคัญของแพลตฟอร์ม ดังนั้นจึงไม่จำเป็นต้องระบุชุดการอ้างอิงที่เล็กลง - ทุกอย่างมีอยู่แล้วคุณจะไม่เปลี่ยนแปลง

NETStandard.Libraryแพคเกจให้ประกอบการอ้างอิงเหล่านี้ จุดหนึ่งของความสับสนคือหมายเลขเวอร์ชันแพ็กเกจคือเวอร์ชัน 1.6.1 แต่ไม่ได้หมายความว่า ".NET Standard 1.6" มันเป็นเพียงเวอร์ชันของแพ็คเกจ

NET Standard เวอร์ชันที่คุณกำหนดเป้าหมายมาจากกรอบเป้าหมายที่คุณระบุในโครงการของคุณ

หากคุณกำลังสร้างไลบรารีและต้องการให้มันทำงานบน. NET Standard 1.3 คุณต้องอ้างอิงNETStandard.Libraryแพ็คเกจซึ่งปัจจุบันเป็นเวอร์ชัน 1.6.1 netstandard1.3แต่ที่สำคัญกว่าไฟล์โครงการของคุณจะกำหนดเป้าหมาย

NETStandard.Libraryแพคเกจจะทำให้คุณมีชุดที่แตกต่างกันของการประกอบการอ้างอิงขึ้นอยู่กับกรอบชื่อเล่นเป้าหมายของคุณ (ฉันลดความซับซ้อนสำหรับระยะเวลาสั้น ๆ แต่คิดว่าlib\netstandard1.0, lib\netstandard1.1และกลุ่มการพึ่งพา ) ดังนั้นหากโครงการของคุณกำหนดเป้าหมายnetstandard1.3คุณจะได้รับชุดอ้างอิง 1.3 หากคุณกำหนดเป้าหมายnetstandard1.6คุณจะได้รับชุดข้อมูลอ้างอิง 1.6 ชุด

หากคุณกำลังสร้างแอปพลิเคชันคุณจะไม่สามารถกำหนดเป้าหมาย. NET Standard ได้ มันไม่สมเหตุสมผล - คุณไม่สามารถทำงานตามข้อกำหนดได้ แต่คุณกำหนดเป้าหมายแพลตฟอร์มที่เป็นรูปธรรมเช่นหรือnet452 netcoreapp1.1NuGet รู้จักการแมประหว่างแพลตฟอร์มเหล่านี้กับnetstandardmonikers เฟรมเวิร์กเป้าหมายดังนั้นรู้ว่าlib\netstandardX.Xโฟลเดอร์ใดที่เข้ากันได้กับแพลตฟอร์มเป้าหมายของคุณ นอกจากนี้ยังรู้ว่าการอ้างอิงNETStandard.Libraryเป็นที่พอใจของแพลตฟอร์มเป้าหมายดังนั้นจะไม่ดึงแอสเซมบลีอื่น ๆ เข้ามา

ในทำนองเดียวกันเมื่อสร้างแอป. NET Core แบบสแตนด์อโลนชุดประกอบการใช้งาน. NET Standard จะถูกคัดลอกไปกับแอปของคุณ การอ้างอิงถึงNETStandard.Libraryไม่นำแอปใหม่อื่น ๆ เข้ามา

โปรดทราบว่าdotnet publishจะสร้างแอปพลิเคชันแบบสแตนด์อโลนแต่ตอนนี้จะไม่ทำการตัดแต่งและจะเผยแพร่แอสเซมบลีทั้งหมด สิ่งนี้จะได้รับการจัดการโดยอัตโนมัติโดยการใช้เครื่องมือดังนั้นอีกครั้งการตัดการอ้างอิงในไลบรารีของคุณจะไม่ช่วยในที่นี้

ที่เดียวที่ฉันนึกได้ว่าจะช่วยลบNETStandard.Libraryข้อมูลอ้างอิงได้ที่ไหนคือถ้าคุณกำหนดเป้าหมายไปที่แพลตฟอร์มที่ไม่รองรับ. NET Standard และคุณสามารถค้นหาแพ็คเกจจาก. บนแพลตฟอร์มเป้าหมายของคุณ ฉันสงสัยว่ามีแพ็คเกจไม่มากพอที่จะเรียกเก็บเงินนั้น


หากคุณทำdotnet publishกับรันไทม์เฉพาะมันจะทำให้เกิดการอ้างอิงทั้งหมดรวมถึง dotnet.exe (หรือเทียบเท่ากับ Linux / OS X) นั่นควรเป็นการปรับใช้แบบสแตนด์อะโลนอย่างสมบูรณ์ ณ จุดนั้น ตรวจสอบผลลัพธ์ของโครงการทดสอบหน่วย: gist.github.com/bradwilson/6cc5a8fdfa18230aa6c99b851fb85c01
Brad Wilson

4
ฉันคิดว่าย่อหน้าสุดท้ายเป็นปัญหาอย่างแน่นอน ... และถ้าไม่ใช่ปัญหาทำไมเราถึงต้องการ netstandard1.x เวอร์ชันต่างๆ ถ้าทุกแพลตฟอร์มมีทุกอย่างใน netstandard1.6 ทำไมถึงมี netstandard1.0 เป็นแนวคิด? นั่นเป็นส่วนที่สับสนสำหรับฉัน
Jon Skeet

1
และรายการแพลตฟอร์มที่รองรับ. NET Standard ไม่รวมแพลตฟอร์ม Unity ใด ๆ
citizenmatt

1
(ความอดทนของคุณเป็นที่ชื่นชมมาก btw ฉันหวังเป็นอย่างยิ่งว่าทั้งหมดนี้จะสมเหตุสมผลและจะเป็นประโยชน์สำหรับนักพัฒนาหลาย ๆ คน ... )
Jon Skeet

1
ขอให้เรายังคงอภิปรายนี้ในการแชท
citizenmatt
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.