एक मेटापेजेज के आधार पर एक नेटस्टैडिट लाइब्रेरी के एप्लिकेशन निहितार्थ क्या हैं?


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 संस्करण। मेरे द्वारा बनाया गया नगेट पैकेज उस निर्भरता को सूचीबद्ध करेगा।

Csproj- आधारित डॉटनेट टूलिंग की बहादुर नई दुनिया में (मैं कमांड लाइन टूल्स के v1.0.1 का उपयोग कर रहा हूं) लक्ष्यीकरण करते समय एक अंतर्निहित मेटापैकेज पैकेज संदर्भ है । इसका मतलब है कि मेरी परियोजना फ़ाइल वास्तव में छोटी है, क्योंकि इसमें स्पष्ट निर्भरता की आवश्यकता नहीं है:NETStandard.Library 1.6.1netstandard1.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 उपयोगकर्ताओं को सिर्फ रूपक पर निर्भर रहने के लिए प्रोत्साहित कर रहा है - लेकिन मैं कैसे हो सकता हूं यकीन है कि जब मैं एक क्लास लाइब्रेरी पैकेज का उत्पादन कर रहा हूं तो इसके नुकसान नहीं हैं?


3
यह ध्यान दिया जाना चाहिए कि निर्भरता ट्रिमिंग पर काम किया जा रहा है । वर्तमान में, Hello World!स्व-सम्‍मिलित एप्लिकेशन का आकार घटाकर <10MB कर दिया जाता है।
एबरनी

एक क्लासिक .NET फ्रेमवर्क सी # हैलो-वर्ल्ड प्रोजेक्ट के < 20KB आकार की तुलना में @ABarney 10MB अभी भी बहुत अधिक है ।
दाई

जवाबों:


76

अतीत में, हमने डेवलपर्स को NETStandard.LibraryNuGet पैकेजों से मेटा पैकेज ( ) का संदर्भ नहीं देने की सिफारिश की है, लेकिन इसके बजाय व्यक्तिगत पैकेज, जैसे System.Runtimeऔर System.Collections। तर्क यह था कि हमने मेटा पैकेज के बारे में सोचा था कि संकुल के एक समूह के लिए शॉर्टहैंड के रूप में। जो .NET प्लेटफ़ॉर्म के वास्तविक परमाणु निर्माण खंड थे। यह धारणा थी: हम एक और .NET प्लेटफॉर्म बना सकते हैं जो केवल इन परमाणु ब्लॉकों में से कुछ का समर्थन करता है, लेकिन उनमें से सभी नहीं। इसलिए, आप जितने कम पैकेजों का संदर्भ देंगे, आप उतने ही अधिक पोर्टेबल होंगे। इस बात को लेकर भी चिंता थी कि बड़े टूल ग्राफ के साथ हमारी टूलींग कैसे निपटती है।

आगे बढ़ते हुए, हम इसे सरल करेंगे:

  1. .NET मानक एक परमाणु निर्माण खंड है । दूसरे शब्दों में, नए प्लेटफॉर्म को .NET मानक को कम करने की अनुमति नहीं है - उन्हें इसे लागू करना होगा।

  2. हम .NET मानक सहित हमारे प्लेटफार्मों का वर्णन करने के लिए पैकेज का उपयोग करने से दूर जा रहे हैं

इसका मतलब है, आपको .NET मानक के लिए किसी भी NuGet संकुल का संदर्भ नहीं देना होगा। आपने अपनी निर्भरता को लिबर फोल्डर के साथ व्यक्त किया, जो कि वास्तव में अन्य सभी .NET प्लेटफ़ॉर्म के लिए, विशेष रूप से .NET फ्रेमवर्क में कैसे काम करता है।

हालाँकि, अभी के संदर्भ में हमारी टूलींग अभी भी जलेगी NETStandard.Library। इसमें कोई बुराई नहीं है, यह सिर्फ आगे बढ़ते हुए बेमानी हो जाएगा।

मैं इस सवाल को शामिल करने के लिए .NET मानक रेपो पर पूछे जाने वाले प्रश्न को अपडेट करूंगा ।

अपडेट : यह सवाल अब एफएक्यू का हिस्सा है


9
धन्यवाद - यह बहुत समझ में आता है। मुझे लगता है कि मैं आंशिक रूप से भ्रमित था क्योंकि प्रोजेक्ट.जॉसन वर्ल्ड में मुझे उस समय भी निर्भरता जोड़ना पड़ा था जब पैकेज तार्किक रूप से मेरे द्वारा लक्षित फ्रेमवर्क का हिस्सा थे (उदाहरण के लिए System.Runtime.Numerics netstandard1.3 के लिए) - इसलिए मुझे यह पसंद किया गया था। वास्तव में उन्हें निर्भरता के रूप में खींच रहा है।
जॉन स्कीट

2
ओह। मुझे पैकेजों को संदर्भित करने का विचार पसंद आया, क्योंकि ऐसा लगा कि मैं केवल "किचन सिंक" के बजाय जो मैं चाहता था, उसका संदर्भ दे सकता हूं। शायद मैं इसके बारे में सही से नहीं सोच रहा हूँ?
नैट बारबेटिनी

3
आप जरूरी नहीं कि इसके बारे में गलत तरीके से सोच रहे हैं, लेकिन सवाल यह है कि आप क्यों परवाह करते हैं। यह समझना महत्वपूर्ण है कि प्लेटफ़ॉर्म असीम रूप से संगत नहीं है। जब आप एक साझा ढांचे के वातावरण (.NET फ्रेमवर्क, मोनो, .NET कोर) में चलते हैं तो ये सभी बिट्स वैसे भी मौजूद होते हैं। यदि आप एक स्व-निहित ऐप (Xamarin, मोनो / .NET कोर लिंकर के साथ) बनाते हैं तो हम आपके वास्तविक उपयोग के आधार पर स्वचालित रूप से ट्रिम कर सकते हैं। किसी भी तरह से, आप छोटे ब्लॉकों को संदर्भित नहीं करके कुछ भी नहीं खो रहे हैं।
इममो लैंडवर्थ

3
संकलक के बारे में क्या नियम लागू होते हैं जैसे कि किसी डेवलपर को व्यावसायिक तर्क परियोजना में http अनुरोध करने से रोकने के लिए उस पैकेज की अनुमति न देकर प्रयास को बर्बाद करना?
डेविड फेरेटी

जरूरी नहीं है, लेकिन आप इसे कैसे लागू करते हैं, अर्थात एक डेवलपर को संदर्भ जोड़ने से क्या रोकता है? मैं एक विश्लेषक लिखता हूं जिसे लेयर नियमों को लागू करने के लिए बिल्ड समय पर इंजेक्ट किया जाता है और बिल्ड मशीन पर त्रुटियों का कारण बनता है।
इममो लैंडवर्थ

19

टीम यह पता लगाने की सिफारिश करती है कि सबसे पतला पैकेज सेट क्या था। वे अब ऐसा नहीं करते हैं, और लोगों को सिर्फ NETStandard.Library में लाने की सलाह देते हैं (एसडीके-शैली परियोजना के मामले में, यह आपके लिए स्वचालित रूप से किया जाएगा)।

मैंने कभी भी पूरी तरह से सीधे जवाब नहीं दिया है कि ऐसा क्यों था, इसलिए मुझे कुछ शिक्षित अनुमान लगाने की अनुमति दें।

प्राथमिक कारण यह होने की संभावना है कि यह उन्हें आश्रित पुस्तकालयों के संस्करणों में अंतर को छिपाने की अनुमति देता है जिसे आपको लक्ष्य रूपरेखा बदलते समय खुद को ट्रैक करने की आवश्यकता होगी। यह एसडीके-आधारित प्रोजेक्ट फ़ाइलों के साथ एक बहुत अधिक उपयोगकर्ता के अनुकूल प्रणाली है, क्योंकि आपको प्लेटफ़ॉर्म का एक अच्छा हिस्सा प्राप्त करने के लिए किसी भी संदर्भ की आवश्यकता नहीं है (जैसे आप डेस्कटॉप-भूमि, विशेष रूप से mscorlib में डिफ़ॉल्ट संदर्भों के साथ उपयोग करते हैं) )।

एक netstandardपुस्तकालय, या netcoreappउपयुक्त NuGet पैकेज में एक एप्लिकेशन होने का अर्थ क्या है, की मेटा-परिभाषा को धकेलने से , उन्हें विज़ुअल स्टूडियो (या dotnet new) के रूप में उन चीजों की परिभाषा में कोई विशेष ज्ञान का निर्माण करने की आवश्यकता नहीं है ।

UWP के लिए देशी संकलन करते समय (कुछ कैविएट के साथ ऐसा) जब स्टैटिक विश्लेषण को प्रकाशित DLL को सीमित करने के लिए उपयोग किया जा सकता है, जो कि वे आज करते हैं। वे आज .NET कोर के लिए ऐसा नहीं करते हैं, लेकिन मुझे लगता है कि यह एक अनुकूलन है जो उन्होंने माना है (साथ ही साथ देशी कोड का समर्थन करते हैं)।

यदि आप ऐसा चुनते हैं तो कुछ भी आपको बहुत चयनात्मक होने से नहीं रोकता है। मेरा मानना है कि आप पाएंगे कि आप लगभग केवल एक ही कर रहा है, जो भी उद्देश्य (क्योंकि यह हर किसी में ला रहा है माना जा जाएगा धरा कर रहे हैं NETStandard.Libraryया Microsoft.NETCore.App)।


6
मैं मानता हूं कि एक बार एक से अधिक निर्भरता होने पर उद्देश्य निश्चित रूप से पराजित होता है, अगर उनमें से कोई भी अंदर लाता है NETStandard.Library। यह कुछ हद तक आत्म-पूर्ति है, निश्चित रूप से ... अगर मैंNETStandard.Library नोदा टाइम पर निर्भर हूं , तो इसका मतलब है कि नोदा टाइम के शीर्ष पर बनी किसी अन्य लाइब्रेरी में निर्भरता को ट्रिम करने का कोई कारण नहीं है, आदि। यह अब के लिए चयनात्मक होने के लिए आकर्षक है (नोदा टाइम है) 2.0 की ओर बढ़ जाना) फिर बाद में थोड़ा सा आराम करें जब एक बार सम्मेलनों की स्थापना हो गई - चयनात्मक से बदलकर lib- आधारित एक गैर-ब्रेकिंग परिवर्तन होगा, मैं मानता हूं, लेकिन रिवर्स सच नहीं है।
जॉन स्कीट

8

आपको निहित संदर्भ को अक्षम करने की आवश्यकता नहीं है। लाइब्रेरी को चलाने में सक्षम सभी प्लेटफार्मों में पहले से ही असेंबली होगी जो कि NETStandard.Libraryनिर्भरता की आवश्यकता होगी।

.NET मानक लाइब्रेरी एक विनिर्देश है, जो संदर्भ असेंबली का एक सेट है जो आप इसके खिलाफ संकलित करते हैं जो एपीआई का एक सेट प्रदान करता है जो प्लेटफार्मों और प्लेटफॉर्म के संस्करणों के एक सेट पर मौजूद होने की गारंटी देता है, जैसे कि .NET कोर या .NET फ्रेमवर्क। । यह इन असेंबली का कार्यान्वयन नहीं है, बस संकलक को आपके कोड को सफलतापूर्वक बनाने की अनुमति देने के लिए एपीआई आकार का पर्याप्त है।

इन एपीआई के कार्यान्वयन को एक लक्ष्य मंच द्वारा प्रदान किया जाता है, जैसे .NET कोर, मोनो या .NET फ्रेमवर्क। वे मंच के साथ जहाज करते हैं, क्योंकि वे मंच का एक अनिवार्य हिस्सा हैं। तो एक छोटी निर्भरता सेट निर्दिष्ट करने की आवश्यकता नहीं है - सब कुछ पहले से ही है, आप इसे नहीं बदलेंगे।

NETStandard.Libraryपैकेज इन संदर्भ विधानसभाओं प्रदान करता है। भ्रम का एक बिंदु संस्करण संख्या है - पैकेज संस्करण 1.6.1 है, लेकिन इसका मतलब ".NET मानक 1.6" नहीं है। यह सिर्फ पैकेज का संस्करण है।

आपके द्वारा लक्षित .NET मानक का संस्करण आपके प्रोजेक्ट में निर्दिष्ट लक्ष्य ढांचे से आता है।

यदि आप एक लाइब्रेरी बना रहे हैं और चाहते हैं कि यह .NET मानक 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 मानक को लक्षित नहीं कर सकते। इसका कोई मतलब नहीं है - आप एक विनिर्देश पर नहीं चल सकते। इसके बजाय, आप ठोस प्लेटफार्मों को लक्षित करते हैं, जैसे net452या netcoreapp1.1। NuGet इन प्लेटफ़ॉर्म और netstandardलक्ष्य फ़्रेमवर्क मॉनीकर्स के बीच मैपिंग को जानता है , इसलिए जानता है कि lib\netstandardX.Xआपके लक्ष्य प्लेटफ़ॉर्म के साथ कौन से फ़ोल्डर संगत हैं। यह भी पता है कि NETStandard.Libraryलक्ष्य मंच द्वारा संतुष्ट होने की निर्भरता है , इसलिए किसी भी अन्य विधानसभाओं में नहीं खींचेंगे।

इसी तरह, एक स्टैंडअलोन .NET कोर ऐप बनाते समय, .NET मानक कार्यान्वयन असेंबलियों को आपके ऐप के साथ कॉपी किया जाता है। संदर्भ NETStandard.Libraryकिसी अन्य नए ऐप में नहीं लाया जाता है।

ध्यान दें कि dotnet publishएक स्टैंडअलोन एप्लिकेशन बनाएगा , लेकिन यह वर्तमान में ट्रिमिंग नहीं करेगा, और सभी विधानसभाओं को प्रकाशित करेगा। यह टूलिंग द्वारा स्वचालित रूप से नियंत्रित किया जाएगा , इसलिए फिर से, आपके पुस्तकालय में निर्भरता को ट्रिम करने से यहां मदद नहीं मिलेगी।

एकमात्र स्थान जिसकी मैं कल्पना कर सकता हूं कि यह संदर्भ को हटाने में मदद कर सकताNETStandard.Library है यदि आप एक प्लेटफ़ॉर्म को लक्षित कर रहे हैं जो .NET मानक का समर्थन नहीं करता है, और आप .NET मानक से एक पैकेज पा सकते हैं जहां सभी सकर्मक निर्भरताएं चल सकती हैं अपने लक्ष्य मंच पर। मुझे संदेह है कि बहुत सारे पैकेज नहीं हैं जो उस बिल को फिट करेंगे।


यदि आप dotnet publishएक विशिष्ट रनटाइम के लिए करते हैं, तो यह सभी निर्भरता में लाएगा, जिसमें dotnet.exe (या इसके लिनक्स / ओएस एक्स समतुल्य) शामिल है। उस बिंदु पर पूरी तरह से अकेले तैनाती होनी चाहिए। एक इकाई परीक्षण परियोजना के लिए परिणाम देखें: gist.github.com/bradwilson/6cc5a8fdfa18230aa6c99b851fb85c01
ब्रैड विल्सन

4
मुझे लगता है कि अंतिम पैराग्राफ ठीक मुद्दा है ... और अगर यह एक मुद्दा नहीं था, तो हमें netstandard1.x के विभिन्न संस्करणों की आवश्यकता क्यों होगी? अगर हर प्लेटफॉर्म में netstandard1.6 सब कुछ है, तो भी netstandard1.0 एक अवधारणा के रूप में क्यों है ? यह मेरे लिए भ्रामक हिस्सा है।
जॉन स्कीट

1
और .NET मानक का समर्थन करने वाले प्लेटफार्मों की सूची में कई एकता प्लेटफार्मों में से कोई भी शामिल नहीं है।
नागरिकमाट

1
(आपके धैर्य की बहुत सराहना की गई है, btw। मैं वास्तव में उम्मीद कर रहा हूं कि यह सब समझ में आएगा, और यह कि कई, कई डेवलपर्स के लिए मदद की जाएगी ...)
जॉन स्कीट

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.