Resolving av extension-metoder
Forstå hvordan kompilatoren finner utvidelser.
Resolving av extension-metoder er en gratis leksjon i C# Academy på CoddyKit. Dette er leksjon 3 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i C# Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i C# Academy inneholder totalt 4 leksjoner.
Hvordan kompilatoren finner utvidelser
Når du skriver value.Method() og ingen samsvarende instansmetode finnes, leter kompilatoren etter en utvidelsesmetode. Men den vurderer bare utvidelser fra navneområder som er tilgjengelige via et using-direktiv.
using-direktiver gjør utvidelser tilgjengelige
En utvidelse er bare synlig hvis du importerer navneområdet. Uten riktig using ser det ut som metoden ikke finnes, selv om den er kompilert inn i assemblyen.
using System;
using MyHelpers; // brings StringExtensions into scope
namespace MyHelpers
{
public static class StringExtensions
{
public static string Reverse(this string s)
{
var arr = s.ToCharArray();
Array.Reverse(arr);
return new string(arr);
}
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("hello".Reverse());
}
}Instansmetoder sjekkes først
Kompilatoren løser kallet i trinn: først søker den etter en samsvarende instans-metode (inkludert nedarvede metoder). Først når ingen passer, søker den etter utvidelsesmetoder.
using System;
using System.Collections.Generic;
public static class ListExt
{
// Ignored: List<int> already has Add(int)
public static void Add(this List<int> list, int a, int b)
=> list.Add(a + b);
}
public class Program
{
public static void Main()
{
var list = new List<int>();
list.Add(5); // the built-in instance Add wins for this signature
Console.WriteLine(list[0]);
}
}Nærmere navneområder foretrekkes
Hvis to utvidelser passer, vinner den som har navneområdet nærmest i nestingshierarkiet. En tvetydighet kompilatoren ikke kan løse, fører til en kompileringsfeil og tvinger deg til å gjøre kallet entydig.
using System;
namespace Outer
{
public static class A { public static string Tag(this int n) => "A" + n; }
namespace Inner
{
public static class B { public static string Tag(this int n) => "B" + n; }
public class Program
{
public static void Main()
{
// B is in the nearer (Inner) namespace, so it is preferred
Console.WriteLine(7.Tag());
}
}
}
}Fjerne tvetydighet med et statisk kall
Når utvidelser kolliderer, eller du vil være eksplisitt, kaller du den statiske metoden direkte ved å bruke hele klassenavnet. Dette omgår oppløsningen av utvidelser fullstendig.
using System;
public static class FormatExt
{
public static string Bracket(this string s) => "[" + s + "]";
}
public class Program
{
public static void Main()
{
// Explicit static call, no ambiguity possible
Console.WriteLine(FormatExt.Bracket("x"));
}
}Overbelastningsoppløsning blant utvidelser
Hvis flere utvidelsesmetoder har samme navn, velger vanlig overbelastningsoppløsning det beste samsvaret basert på parametertypene, akkurat som ved vanlig overbelastning av metoder.
using System;
public static class PrintExt
{
public static string Describe(this int n) => "int:" + n;
public static string Describe(this string s) => "str:" + s;
}
public class Program
{
public static void Main()
{
Console.WriteLine(42.Describe());
Console.WriteLine("hi".Describe());
}
}Generisk typeinferens under oppløsning
For generiske utvidelser utleder kompilatoren typeargumentene fra mottakeren og argumentene. Hvis inferensen mislykkes, vurderes ikke utvidelsen.
using System;
using System.Collections.Generic;
public static class SeqExt
{
public static T FirstItem<T>(this IEnumerable<T> source)
{
foreach (var item in source) return item;
throw new InvalidOperationException("empty");
}
}
public class Program
{
public static void Main()
{
var nums = new List<int> { 5, 6, 7 };
// T inferred as int from the List<int> receiver
Console.WriteLine(nums.FirstItem());
}
}Globale using-direktiver og implisitte importer
Moderne C# kan deklarere global using-direktiver slik at et navneområde er tilgjengelig i hele prosjektet. Dermed blir delte utvidelsesbiblioteker tilgjengelige overalt uten at importene må gjentas.
using System;
// In a real project a separate file might say: global using MyHelpers;
namespace MyHelpers
{
public static class IntExt { public static int Twice(this int n) => n * 2; }
}
public class Program
{
public static void Main()
{
// Works here because MyHelpers is referenced explicitly
Console.WriteLine(MyHelpers.IntExt.Twice(8));
}
}Når mottakertypen har betydning
Oppløsningen avhenger av mottakerens statiske type, ikke kjøretidstypen. En utvidelse som er deklarert for en basetype, gjelder selv når variabelen inneholder en instans av en avledet type, med mindre en mer spesifikk utvidelse er tilgjengelig.
using System;
public class Animal { }
public class Cat : Animal { }
public static class AnimalExt
{
public static string Kind(this Animal a) => "animal";
}
public class Program
{
public static void Main()
{
Animal a = new Cat();
// Chosen by static type Animal
Console.WriteLine(a.Kind());
}
}En mental modell for oppløsning
Tenk på rekkefølgen slik: (1) instansmetoder, deretter (2) utvidelsesmetoder fra importerte navneområder, nærmeste først, og deretter (3) overbelastningsoppløsning blant kandidatene. Når du kjenner denne rekkefølgen, forklarer den nesten alle overraskende resultater.
using System;
public static class Ext
{
public static string Wrap(this string s) => "<" + s + ">";
}
public class Program
{
public static void Main()
{
// No instance Wrap exists, so the extension is used
Console.WriteLine("node".Wrap());
}
}Prøv selv
Definer en utvidelse i et navneområde, importer det, og kall den. Kall deretter samme metode eksplisitt som en statisk metode for å se at begge fremgangsmåtene fungerer.
using System;
using Text.Helpers;
namespace Text.Helpers
{
public static class StringExtensions
{
public static int Vowels(this string s)
{
int count = 0;
foreach (var c in s.ToLower())
if ("aeiou".IndexOf(c) >= 0) count++;
return count;
}
}
}
public class Program
{
public static void Main()
{
Console.WriteLine("education".Vowels());
Console.WriteLine(Text.Helpers.StringExtensions.Vowels("education"));
}
}Hurtigsjekk
Tenk over hva som gjør en utvidelsesmetode synlig.
Oppsummering
Oppløsning av utvidelsesmetoder følger en tydelig rekkefølge.
- Instansmetoder prøves først; utvidelser fyller bare hullene.
- En utvidelse er bare synlig hvis navneområdet er i omfang via
usingellerglobal using. - Nærmere navneområder vinner; uavklarte like resultater gir kompileringsfeil.
- Du kan alltid kalle den statiske metoden eksplisitt for å fjerne tvetydighet.
- Oppløsningen bruker mottakerens statiske type.
Lær deg C# med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 93
- Leksjoner
- 346
Ofte stilte spørsmål
Er leksjonen «Resolving av extension-metoder» gratis?
Ja – hele teksten i «Resolving av extension-metoder» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av C# Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i C# Academy inneholder totalt 4 leksjoner.
Hva lærer jeg i «Resolving av extension-metoder»?
Forstå hvordan kompilatoren finner utvidelser. Du øver på C# Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med C# Academy?
Ingen tidligere erfaring er nødvendig. C# Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.
Hvor lang tid tar leksjonen «Resolving av extension-metoder»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne C# Academy-leksjonen?
Ja. Alle C# Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Definere extension-metoder
- Utvide grensesnitt og generiske typer
- Resolving av extension-metoder
- Utforme gode extension-metoder