0Pricing
C# Academy · 课时

泛型数学(概览)与泛型特性(适用时)

不使用现代特性来模拟泛型数学:传入运算提供者或委托,谨慎约束类型,并通过 Type 参数模拟“泛型特性”。

泛型数学(概览)与泛型特性(适用时) 是 CoddyKit 上的免费 C# Academy 课时。 这是第 2 节课,共 3 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 3 节课。

C# 6 中的泛型数学

目标:在 C# 6 中以泛型方式编写数值算法。

  • T 上没有静态抽象运算符
  • 替代方案:运算提供器接口或小型委托
  • 对于特性,请使用带有Type参数的特性

运算提供器模式

通过接口提供零值和Add。泛型算法调用这些方法,而不是对 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);
  }
}

使用辅助方法计算平均值

对于无法以泛型方式表达的运算(例如除法),请传入小型转换器或额外的委托。

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);
  }
}

基于委托的折叠

委托可以让实现保持精简:传入种子值和组合函数。它适合小型工具方法。

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);
  }
}

特性替代方案

C# 6 中没有真正的泛型特性。可以将 Type 传给特性,以指示相关的泛型类型。

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);
    }
  }
}

提示与选择

提示:

  • 对于可复用的数值算法,优先使用运算提供器。
  • 对于小型辅助方法(组合、转换),使用委托。
  • 对于特性,在特性中传入Type,再通过反射读取它。

泛型数学替代方案

快速检查:在 C# 6 中,如果没有现代泛型数学功能,编写泛型求和方法的实用方式是什么?

回顾

回顾:没有现代泛型数学功能时,请将运算或委托传给算法。对于特性,请使用携带Type的特性,并通过反射读取它。

常见问题解答

「泛型数学(概览)与泛型特性(适用时)」课时是免费的吗?

是的 — 「泛型数学(概览)与泛型特性(适用时)」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 3 节课。

「泛型数学(概览)与泛型特性(适用时)」这节课中我会学到什么?

不使用现代特性来模拟泛型数学:传入运算提供者或委托,谨慎约束类型,并通过 Type 参数模拟“泛型特性”。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 2 节课,共 3 节。

「泛型数学(概览)与泛型特性(适用时)」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. unmanaged、notnull、new()(C# 6 模拟)
  2. 泛型数学(概览)与泛型特性(适用时)
  3. 可复用的泛型工具
← 返回 C# Academy