Megosztás a következőn keresztül:


.NET MAUI-alkalmazás optimalizálása

Az alkalmazás létrehozásakor a .NET többplatformos alkalmazás felhasználói felülete (.NET MAUI) használhat egy ILLink nevű linkert az alkalmazás általános méretének csökkentéséhez egy úgynevezett vágási technikával. ILLink csökkenti a méretet a fordító által létrehozott köztes kód elemzésével. Eltávolítja a nem használt metódusokat, tulajdonságokat, mezőket, eseményeket, szerkezeteket és osztályokat egy olyan alkalmazás létrehozásához, amely csak az alkalmazás futtatásához szükséges kód- és szerelvényfüggőségeket tartalmazza.

Az alkalmazások levágásakor bekövetkező viselkedésváltozások megakadályozása érdekében a .NET a vágási kompatibilitás statikus elemzését teszi lehetővé vágási figyelmeztetések használatával. A vágógép vágási figyelmeztetéseket hoz létre, amikor olyan kódot talál, amely nem kompatibilis a vágással. Ha vannak vágási figyelmeztetések, ezeket ki kell javítani, és a vágás után alaposan tesztelni kell az alkalmazást annak érdekében, hogy ne változhasson a viselkedés. További információkért lásd: Bevezetés a vágási figyelmeztetésekbe.

Vágási folyamat

A vágási viselkedés úgy szabályozható, hogy a $(TrimMode) build tulajdonságot partial vagy fullértékre állítjuk.

<PropertyGroup>
  <TrimMode>full</TrimMode>
</PropertyGroup>

Fontos

A $(TrimMode) build tulajdonságot nem szabad a buildkonfiguráció határozza meg. Ennek az az oka, hogy a funkciók kapcsolói a $(TrimMode) buildtulajdonság értéke alapján vannak engedélyezve vagy letiltva, és minden buildkonfigurációban engedélyezni vagy letiltani kell ugyanazokat a funkciókat, hogy a kód azonos módon viselkedjen.

A full vágási mód eltávolítja az alkalmazás által nem használt kódot. A partial vágási mód levágja az alaposztály-kódtárat (BCL), az alapul szolgáló platformok (például Mono.Android.dll és Microsoft.iOS.dll) szerelvényeket, valamint azokat a szerelvényeket, amelyek a $(TrimmableAsssembly) összeállítási elemhez való vágást űzték:

<ItemGroup>
  <TrimmableAssembly Include="MyAssembly" />
</ItemGroup>

Ez egyenértékű a [AssemblyMetadata("IsTrimmable", "True")] beállításával a szerelvény létrehozásakor.

Jegyzet

Nem szükséges a $(PublishTrimmed) buildtulajdonságot úgy beállítani, hogy true legyen az alkalmazás projektfájljában, mert ez alapértelmezés szerint be van állítva.

További vágási beállításokért lásd .

Az alapértelmezett vágási beállítások

Alapértelmezés szerint az Android- és Mac Catalyst-buildek részleges vágást használnak, ha a buildkonfiguráció kiadási buildre van állítva. Az iOS részleges vágást használ az eszköz buildjeihez, függetlenül a buildkonfigurációtól, és nem használ vágást szimulátor-buildekhez.

Inkompatibilitások vágása

A következő .NET MAUI-funkciók nem kompatibilisek a teljes vágással, és a vágó eltávolítja őket:

Alternatív megoldásként használhat funkciókapcsolókat is, hogy a vágó megőrizze ezeknek a funkcióknak a kódját. További információért lásd: Trimming funkciókapcsolók.

A .NET trimmelési inkompatibilitásairól lásd: Ismert trimmelési inkompatibilitások.

TypeConverter definiálása implicit konverziós operátor helyére

Nem lehet implicit konverziós operátorokra támaszkodni, ha inkompatibilis típusú értéket rendel egy XAML-tulajdonsághoz, vagy ha két különböző típusú tulajdonság használ adatkötést, ha engedélyezve van a teljes vágás. Ennek az az oka, hogy az implicit operátori metódusokat a vágó eltávolíthatja, ha nem használják őket a C#-kódban. További információ az implicit konverziós operátorokról: Felhasználó által definiált explicit és implicit konverziós operátorok.

Vegyük például az alábbi típust, amely implicit konverziós operátorokat határoz meg SizeRequest és Sizeközött:

namespace MyMauiApp;

public struct SizeRequest : IEquatable<SizeRequest>
{
    public Size Request { get; set; }
    public Size Minimum { get; set; }

    public SizeRequest(Size request, Size minimum)
    {
        Request = request;
        Minimum = minimum;
    }

    public SizeRequest(Size request)
    {
        Request = request;
        Minimum = request;
    }

    public override string ToString()
    {
        return string.Format("{{Request={0} Minimum={1}}}", Request, Minimum);
    }

    public bool Equals(SizeRequest other) => Request.Equals(other.Request) && Minimum.Equals(other.Minimum);

    public static implicit operator SizeRequest(Size size) => new SizeRequest(size);
    public static implicit operator Size(SizeRequest size) => size.Request;
    public override bool Equals(object? obj) => obj is SizeRequest other && Equals(other);
    public override int GetHashCode() => Request.GetHashCode() ^ Minimum.GetHashCode();
    public static bool operator ==(SizeRequest left, SizeRequest right) => left.Equals(right);
    public static bool operator !=(SizeRequest left, SizeRequest right) => !(left == right);
}

Ha a teljes vágás engedélyezve van, a SizeRequest és Size közötti implicit konverziós operátorokat a vágó eltávolíthatja, ha nem használják őket a C# kódban.

Ehelyett definiáljon egy TypeConverter-t a típus számára, és csatolja a TypeConverterAttribute-et a típushoz.

using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;

namespace MyMauiApp;

[TypeConverter(typeof(SizeRequestTypeConverter))]
public struct SizeRequest : IEquatable<SizeRequest>
{
    public Size Request { get; set; }
    public Size Minimum { get; set; }

    public SizeRequest(Size request, Size minimum)
    {
        Request = request;
        Minimum = minimum;
    }

    public SizeRequest(Size request)
    {
        Request = request;
        Minimum = request;
    }

    public override string ToString()
    {
        return string.Format("{{Request={0} Minimum={1}}}", Request, Minimum);
    }

    public bool Equals(SizeRequest other) => Request.Equals(other.Request) && Minimum.Equals(other.Minimum);

    public static implicit operator SizeRequest(Size size) => new SizeRequest(size);
    public static implicit operator Size(SizeRequest size) => size.Request;
    public override bool Equals(object? obj) => obj is SizeRequest other && Equals(other);
    public override int GetHashCode() => Request.GetHashCode() ^ Minimum.GetHashCode();
    public static bool operator ==(SizeRequest left, SizeRequest right) => left.Equals(right);
    public static bool operator !=(SizeRequest left, SizeRequest right) => !(left == right);

    private sealed class SizeRequestTypeConverter : TypeConverter
    {
        public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
            => sourceType == typeof(Size);

        public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
            => value switch
            {
                Size size => (SizeRequest)size,
                _ => throw new NotSupportedException()
            };

        public override bool CanConvertTo(ITypeDescriptorContext? context, [NotNullWhen(true)] Type? destinationType)
            => destinationType == typeof(Size);

        public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
        {
            if (value is SizeRequest sizeRequest)
            {
                if (destinationType == typeof(Size))
                    return (Size)sizeRequest;
            }
            throw new NotSupportedException();
        }
    }
}

Trimmelési funkciókapcsolók

A .NET MAUI rendelkezik trimmer-irányelvekkel, amelyek funkciókapcsolókként is ismertek, és amelyek lehetővé teszik a kód megőrzését olyan funkciók esetében, amelyeknél a vágás nem biztonságos. Ezek a nyesési irányelvek akkor használhatók, ha a $(TrimMode) buildtulajdonság full-re van állítva, valamint a natív AOT esetében is.

MSBuild tulajdonság Leírás
MauiEnableVisualAssemblyScanning Ha trueértékre van állítva, a .NET MAUI megvizsgálja a szerelvényeket a IVisual-t implementáló típusok és a [assembly:Visual(...)] attribútumokkal rendelkező típusok után, majd regisztrálja ezeket a típusokat. Ez a buildtulajdonság alapértelmezés szerint false, ha engedélyezve van a teljes vágás.
MauiShellSearchResultsRendererDisplayMemberNameSupported Ha falseértékre van állítva, a SearchHandler.DisplayMemberName értéke figyelmen kívül lesz hagyva. Ehelyett meg kell adnia a ItemTemplate-t a SearchHandler eredmények megjelenésének meghatározásához. Alapértelmezés szerint ez a build-tulajdonság false-ra van állítva, amikor a teljes ritkítás vagy a natív AOT engedélyezve van.
MauiQueryPropertyAttributeSupport Ha falseértékre van állítva, [QueryProperty(...)] attribútumok nem használhatók a tulajdonságértékek beállítására navigáláskor. Ehelyett a IQueryAttributable felületet kell implementálnia a lekérdezési paraméterek elfogadásához. Alapértelmezés szerint ez a buildtulajdonság false-ra van állítva, ha a teljes metszés vagy a Natív AOT engedélyezve van.
MauiImplicitCastOperatorsUsageViaReflectionSupport Ha falseértékre van állítva, a .NET MAUI nem fog implicit konverziós operátorokat keresni az értékek egyik típusból a másikba való konvertálásakor. Ez hatással lehet a különböző típusú tulajdonságok közötti kötésekre, valamint egy más típusú kötésű objektum tulajdonságértékének beállítására. Ehelyett definiáljon egy TypeConverter definíciót a típushoz, és csatolja a típushoz a TypeConverterAttribute attribútum használatával. Alapértelmezés szerint, ha a teljes trimmelés vagy a natív AOT engedélyezve van, ez a build tulajdonság false.
_MauiBindingInterceptorsSupport Ha falseértékre van állítva, a .NET MAUI nem fogja elfogni a SetBinding metódusokra irányuló hívásokat, és nem próbálja meg lefordítani őket. Alapértelmezés szerint ennek a buildtulajdonságnak az értéke true.
MauiEnableXamlCBindingWithSourceCompilation Ha trueértékre van állítva, a .NET MAUI az összes kötést lefordítja, beleértve azokat is, ahol a Source tulajdonságot használják. Ha engedélyezi ezt a funkciót, győződjön meg arról, hogy minden kapcsolat rendelkezzen a megfelelő x:DataType-val a fordításhoz, vagy törölje az adattípust x:Data={x:Null}}, ha nem kell a kapcsolatokat fordítani. Alapértelmezés szerint ez a build tulajdonság true-ra van állítva, ha engedélyezve van a teljes metszés vagy a natív AOT.
MauiHybridWebViewSupported Ha falseértékre van állítva, a HybridWebView vezérlő nem lesz elérhető. Alapértelmezés szerint ez a build tulajdonság false-ra van állítva, ha a teljes trimmelés vagy a natív AOT engedélyezve van.

Ezek az MSBuild tulajdonságok egyenértékű AppContext kapcsolókkal is rendelkeznek:

  • Az MauiEnableVisualAssemblyScanning MSBuild tulajdonságnak van egy érvényes AppContext kapcsolója, amelynek neve Microsoft.Maui.RuntimeFeature.IsIVisualAssemblyScanningEnabled.
  • Az MauiShellSearchResultsRendererDisplayMemberNameSupported MSBuild tulajdonság Microsoft.Maui.RuntimeFeature.IsShellSearchResultsRendererDisplayMemberNameSupportednevű egyenértékű AppContext kapcsolóval rendelkezik.
  • Az MauiQueryPropertyAttributeSupport MSBuild tulajdonság Microsoft.Maui.RuntimeFeature.IsQueryPropertyAttributeSupportednevű egyenértékű AppContext kapcsolóval rendelkezik.
  • Az MauiImplicitCastOperatorsUsageViaReflectionSupport MSBuild tulajdonságnak van egy Microsoft.Maui.RuntimeFeature.IsImplicitCastOperatorsUsageViaReflectionSupportednevű egyenértékű AppContext kapcsolója.
  • Az _MauiBindingInterceptorsSupport MSBuild tulajdonságnak van egy AppContext kapcsoló nevű egyenértékűje, amelyet Microsoft.Maui.RuntimeFeature.AreBindingInterceptorsSupported-nek hívnak.
  • Az MauiEnableXamlCBindingWithSourceCompilation MSBuild tulajdonságnak van egy AppContext kapcsolóval egyenértékű kapcsolója, amelyet Microsoft.Maui.RuntimeFeature.MauiEnableXamlCBindingWithSourceCompilationEnabled-nek hívnak.
  • Az MauiHybridWebViewSupported MSBuild tulajdonságnak van egy Microsoft.Maui.RuntimeFeature.IsHybridWebViewSupportednevű egyenértékű AppContext kapcsolója.

A funkciókapcsolók legegyszerűbben úgy használhatók, ha a megfelelő MSBuild tulajdonságot az alkalmazás projektfájljába (*.csproj) helyezik, ami miatt a kapcsolódó kód le lesz vágva a .NET MAUI-szerelvényekből.

Kód megőrzése

Ha a vágót használja, az néha eltávolítja a dinamikusan, akár közvetetten is meghívható kódot. Megadhatja a vágónak az utasítást, hogy őrizze meg a tagokat azáltal, hogy ellátja őket a DynamicDependency attribútummal. Ez az attribútum a tagok típusától és részhalmazától, illetve adott tagoktól való függőség kifejezésére használható.

Fontos

A BCL minden olyan tagjának eltávolítására van szükség, amelyről nem állapítható meg statikusan, hogy az alkalmazás használja.

A DynamicDependency attribútum konstruktorokra, mezőkre és metódusokra alkalmazható:

[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
    var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
    helper.Invoke(null, null);
}

Ebben a példában a DynamicDependency biztosítja, hogy a Helper metódus megmarad. Az attribútum nélkül a vágás eltávolítja Helper -t a MyAssembly -ből, vagy teljesen eltávolítja MyAssembly -t, ha nincs másutt hivatkozva rá.

Az attribútum egy string vagy a DynamicallyAccessedMembers attribútumon keresztül adja meg a megtartandó tagot. A típus és a szerelvény implicit módon szerepel az attribútumkörnyezetben, vagy explicit módon meg van adva az attribútumban (Typevagy strings a típus és a szerelvény neve alapján).

A típus- és tagsztringek a C#-dokumentáció megjegyzésazonosító-sztringjének egy változatát, a formátumot használják, a tagelőtag nélkül,. A tagsztring nem tartalmazhatja a deklarálási típus nevét, és kihagyhatja a paramétereket a megadott név összes tagjának megtartásához. Az alábbi példák érvényes felhasználási módokat mutatnak be:

[DynamicDependency("Method()")]
[DynamicDependency("Method(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
[DynamicDependency("GenericMethod``2(``0,``1)")]
[DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]

Szerelvények megőrzése

Megadhatja azokat a szerelvényeket, amelyeket ki kell zárni a vágási folyamatból, miközben más szerelvényeket is levághat. Ez a módszer akkor lehet hasznos, ha nem tudja könnyen használni a DynamicDependency attribútumot, vagy nem tudja szabályozni a levágott kódot.

Ha az összes szerelvényt levágja, megadhatja a vágónak, hogy hagyja ki a szerelvényt, ha beállít egy TrimmerRootAssembly MSBuild elemet a projektfájlban:

<ItemGroup>
  <TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>

Jegyzet

A .dll bővítmény nem szükséges az TrimmerRootAssembly MSBuild tulajdonság beállításakor.

Ha a nyíró kihagy egy összeszerelést, akkor gyökérkénttekinthető, ami azt jelenti, hogy az és az összes statikusan értett függősége megmarad. Más összeállításokat kihagyhat, ha további TrimmerRootAssembly MSBuild tulajdonságokat ad hozzá a <ItemGroup>.

Szerelvények, típusok és tagok megőrzése

A vágónak átadhat egy XML-leírásfájlt, amely meghatározza, hogy mely szerelvényeket, típusokat és tagokat kell megőrizni.

Ha ki szeretne zárni egy tagot a vágási folyamatból az összes szerelvény levágásakor, állítsa a TrimmerRootDescriptor MSBuild elemet a projektfájlban arra az XML-fájlra, amely meghatározza a kizárni kívánt tagokat:

<ItemGroup>
  <TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>

Az XML-fájl ezután a jelölőt használja formátumban annak meghatározására, hogy mely tagokat kell kizárni:

<linker>
  <assembly fullname="MyAssembly">
    <type fullname="MyAssembly.MyClass">
      <method name="DynamicallyAccessedMethod" />
    </type>
  </assembly>
</linker>

Ebben a példában az XML-fájl egy olyan metódust határoz meg, amelyet az alkalmazás dinamikusan elér, és amely nincs kizárva a vágásból.

Ha egy szerelvény, típus vagy tag szerepel az XML-ben, az alapértelmezett művelet a megőrzés, ami azt jelenti, hogy függetlenül attól, hogy a vágó azt használja-e vagy sem, megmarad a kimenetben.

Jegyzet

A tartósítási címkék nem egyértelműek. Ha nem adja meg a következő részletességi szintet, az az összes gyermekre kiterjed. Ha egy szerelvény típusok nélkül szerepel a listán, akkor a rendszer megőrzi a szerelvény összes típusát és tagját.

Szerelvény megjelölése vágásbiztosként

Ha van egy kódtár a projektben, vagy Ön egy újrafelhasználható kódtár fejlesztője, és azt szeretné, hogy a vágó a szerelvényt vághatóként kezelje, a szerelvényt vágásbiztosként megjelölheti úgy, hogy hozzáadja a IsTrimmable MSBuild tulajdonságot a szerelvény projektfájljához:

<PropertyGroup>
    <IsTrimmable>true</IsTrimmable>
</PropertyGroup>

Ez "vághatóként" jelöli meg a szerelvényt, és engedélyezi az adott projektre vonatkozó vágási figyelmeztetéseket. A "vágható" állapot azt jelenti, hogy a szerelvény kompatibilisnek tekinthető a vágással, és a szerelvény létrehozásakor nem lehetnek vágási figyelmeztetések. Ha egy optimalizált alkalmazásban használják, a rendszer eltávolítja az összetevő nem használt elemeit a végső kimenetben.

Ha natív AOT-telepítést használ a .NET 9+-ban, a IsAotCompatible MSBuild tulajdonság beállítása true a IsTrimmable tulajdonsághoz is hozzárendel egy true értéket, és további AOT-elemző buildtulajdonságokat tesz lehetővé. További információ az AOT-elemzőkről: AOT-kompatibilis elemzők. További információért a .NET MAUI natív AOT-üzembe helyezéséről lásd: - natív AOT-üzembe helyezés -.

Ha a projektfájlban beállítja a(z) IsTrimmable MSBuild tulajdonságot true értékre, a AssemblyMetadata attribútumot beszúrja az összeállításba.

[assembly: AssemblyMetadata("IsTrimmable", "True")]

Másik lehetőségként hozzáadhatja a AssemblyMetadata attribútumot a szerelvényhez anélkül, hogy hozzáadta volna a IsTrimmable MSBuild tulajdonságot a szerelvény projektfájljához.

Jegyzet

Ha a IsTrimmable MSBuild tulajdonság be van állítva egy szerelvényhez, ez felülbírálja a AssemblyMetadata("IsTrimmable", "True") attribútumot. Ez lehetővé teszi, hogy a szerelvényt akkor is levágja, ha nem rendelkezik az attribútummal, vagy letiltsa az attribútummal rendelkező szerelvény levágását.

Elemzési figyelmeztetések mellőzése

Ha a vágóegység engedélyezve van, eltávolítja a statikusan nem elérhető IL-t. A dinamikus függőségeket létrehozó tükröződéseket vagy más mintákat használó alkalmazások emiatt megszakadhatnak. Az ilyen mintákra való figyelmeztetéshez, amikor egy szerelvényt vágásbiztosként jelöl meg, a könyvtár-szerzőknek a SuppressTrimAnalysisWarnings MSBuild tulajdonságot falseértékre kell állítaniuk:

<PropertyGroup>
  <SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>

A vágáselemzési figyelmeztetések figyelmen kívül hagyása a teljes alkalmazásra vonatkozó figyelmeztetéseket be fogja vonni, beleértve a saját kódját, a könyvtár kódját és az SDK kódját is.

Részletes figyelmeztetések megjelenítése

A vágáselemzés legfeljebb egy figyelmeztetést eredményez minden olyan összeállításhoz, amely egy PackageReference-ból származik, ami azt jelzi, hogy az összeállítás belső elemei nem kompatibilisek az optimalizálással. Kódtár-szerzőként, ha egy szerelvényt vágásbiztosként jelöl meg, az TrimmerSingleWarn MSBuild tulajdonság falsebeállításával engedélyezheti az egyes szerelvényekre vonatkozó figyelmeztetéseket:

<PropertyGroup>
  <TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>

Ez a beállítás az összes részletes figyelmeztetést megjeleníti ahelyett, hogy szerelvényenként egyetlen figyelmeztetésre összecsukja őket.

Lásd még: