0Pricing
C# Academy · Lekcja

Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)

Proszę emulować matematykę generyczną bez nowoczesnych funkcji: przekazywać dostawcę operacji lub delegaty, ostrożnie ograniczać typy oraz symulować „atrybuty generyczne” za pomocą parametrów Type.

Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie) to bezpłatna lekcja C# Academy na CoddyKit. To lekcja 2 z 3. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej C# Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs C# Academy zawiera 3 lekcji w sumie.

Arytmetyka generyczna w C# 6

Cel: Pisać generyczne algorytmy numeryczne w C# 6.

  • Brak statycznych abstrakcyjnych operatorów dla T
  • Obejścia: interfejs ops-provider lub małe delegaty
  • W przypadku adnotacji należy używać atrybutów z parametrami Type

Wzorzec ops-provider

Należy udostępnić Zero i Add za pośrednictwem interfejsu. Algorytm generyczny wywołuje te metody zamiast używać operatora + dla T.

using System;
using System.Collections.Generic;

public interface INumericOps<T>
{
  T Zero { get; }
  T Add(T a, T b);
}

public sealed class IntOps : INumericOps<int>
{
  public int Zero { get { return 0; } }
  public int Add(int a, int b) { return a + b; }
}

public sealed class DoubleOps : INumericOps<double>
{
  public double Zero { get { return 0.0; } }
  public double Add(double a, double b) { return a + b; }
}

public class Program
{
  static T Sum<T>(IEnumerable<T> items, INumericOps<T> ops)
  {
    T acc = ops.Zero;
    foreach (T x in items) acc = ops.Add(acc, x);
    return acc;
  }

  public static void Main(string[] args)
  {
    int s1 = Sum(new int[] {1,2,3}, new IntOps());
    double s2 = Sum(new double[] {1.5, 2.0}, new DoubleOps());
    Console.WriteLine("Sum int = " + s1);
    Console.WriteLine("Sum double = " + s2);
  }
}

Średnia z pomocnikami

W przypadku operacji, których nie można wyrazić generycznie (takich jak dzielenie), należy przekazać mały konwerter lub dodatkowy delegat.

using System;
using System.Collections.Generic;

public interface INumericOps<T>
{
  T Zero { get; }
  T Add(T a, T b);
}

public sealed class DoubleOps : INumericOps<double>
{
  public double Zero { get { return 0.0; } }
  public double Add(double a, double b) { return a + b; }
}

public class Program
{
  static double Average<T>(IEnumerable<T> items, INumericOps<T> ops, Func<T,double> toDouble)
  {
    T acc = ops.Zero;
    int count = 0;
    foreach (T x in items) { acc = ops.Add(acc, x); count++; }
    if (count == 0) throw new ArgumentException("Empty sequence", "items");
    // convert with a delegate for division
    return toDouble(acc) / count;
  }

  public static void Main(string[] args)
  {
    double avg = Average<double>(new double[] {2.0, 4.0, 6.0}, new DoubleOps(), delegate(double d) { return d; });
    Console.WriteLine("Avg = " + avg);
  }
}

Fold oparty na delegacie

Delegaty pozwalają zachować minimalną implementację: należy przekazać wartość początkową i funkcję łączącą. To dobre rozwiązanie dla niewielkich narzędzi.

using System;

public class Program
{
  static T Fold<T>(T[] xs, T seed, Func<T,T,T> combine)
  {
    T acc = seed;
    for (int i = 0; i < xs.Length; i++) acc = combine(acc, xs[i]);
    return acc;
  }

  public static void Main(string[] args)
  {
    int sum = Fold<int>(new int[] {1,2,3}, 0, delegate(int a, int b) { return a + b; });
    double sumD = Fold<double>(new double[] {1.5, 2.5}, 0.0, delegate(double a, double b) { return a + b; });
    Console.WriteLine("Sum ints = " + sum);
    Console.WriteLine("Sum doubles = " + sumD);
  }
}

Obejście dotyczące atrybutów

W C# 6 nie ma prawdziwych atrybutów generycznych. Należy przekazać Type do atrybutu, aby wskazać powiązany typ generyczny.

using System;
using System.Reflection;

// C# 6 cannot declare generic attributes. Workaround: pass a Type.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ValidatorForAttribute : Attribute
{
  public Type TargetType { get; private set; }
  public ValidatorForAttribute(Type targetType) { TargetType = targetType; }
}

public sealed class Customer { public string Name; }

[ValidatorFor(typeof(Customer))]
public sealed class CustomerValidator
{
  public bool IsValid(Customer c) { return c != null && !string.IsNullOrEmpty(c.Name); }
}

public class Program
{
  public static void Main(string[] args)
  {
    Type t = typeof(CustomerValidator);
    object[] attrs = t.GetCustomAttributes(typeof(ValidatorForAttribute), false);
    if (attrs.Length > 0)
    {
      ValidatorForAttribute a = (ValidatorForAttribute)attrs[0];
      Console.WriteLine("Validator targets: " + a.TargetType.Name);
    }
  }
}

Wskazówki i wybory

Wskazówki:

  • Należy preferować ops-provider w przypadku wielokrotnego użycia algorytmów numerycznych.
  • Należy używać delegatów w małych pomocnikach (combine, convert).
  • W przypadku adnotacji należy przekazywać Type w atrybutach i odczytywać go za pomocą refleksji.

Obejście dla arytmetyki generycznej

Szybkie sprawdzenie: Jak w C# 6 praktycznie napisać generyczne Sum bez używania nowoczesnej arytmetyki generycznej?

Podsumowanie

Podsumowanie: Bez nowoczesnej arytmetyki generycznej należy przekazywać do algorytmów ops lub delegaty. W przypadku adnotacji należy używać atrybutów zawierających Type i odczytywać go za pomocą refleksji.

Często zadawane pytania

Czy lekcja „Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)” jest bezpłatna?

Tak — pełny tekst „Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu C# Academy, przejdź na CoddyKit PRO. Kurs C# Academy zawiera 3 lekcji w sumie.

Co nauczysz się w „Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)”?

Proszę emulować matematykę generyczną bez nowoczesnych funkcji: przekazywać dostawcę operacji lub delegaty, ostrożnie ograniczać typy oraz symulować „atrybuty generyczne” za pomocą parametrów Type. Ćwiczysz C# Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć C# Academy?

Nie wymagamy żadnego doświadczenia. C# Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 3.

Ile czasu zajmuje lekcja „Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji C# Academy?

Tak. Każda lekcja C# Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. unmanaged, notnull, new() (emulacja w C# 6)
  2. Matematyka generyczna (omówienie), atrybuty generyczne (gdy mają zastosowanie)
  3. Wielokrotnego użytku narzędzia generyczne
← Powrót do C# Academy