C# 泛型特化

Wesley13 等级 177 0 0
标签: 泛型

C# 泛型不是 C++ 的模板类,并不支持特化和偏特化,但是使用一些技巧可以在一定程度上达到相同的目的。

原文是 po 在 stackoverflow 上的一个回答:A: Generic indexer overload specialization

一、泛型方法的特化

使用一个非泛型 helper 类和一个内嵌的泛型类可以实现对泛型方法的特化。

    internal static class IndexerImpl //non-generic static helper class
    {
        private static T IndexerDefaultImpl<T>(int i) => default(T); //default implementation

        private static T IndexerImpl2<T>(int i) => default(T); //another implementation for short/int/long

        private static string IndexerForString(int i) => (i * i).ToString(); //specialization for T=string
        private static DateTime IndexerForDateTime(int i) => new DateTime(i * i * i); //specialization for T=DateTime

        static IndexerImpl() //install the specializations
        {
            Specializer<string>.Fun = IndexerForString;
            Specializer<DateTime>.Fun = IndexerForDateTime;

            Specializer<short>.Fun = IndexerImpl2<short>;
            Specializer<int>.Fun = IndexerImpl2<int>;
            Specializer<long>.Fun = IndexerImpl2<long>;
        }

        internal static class Specializer<T> //specialization dispatcher
        {
            internal static Func<int, T> Fun;
            internal static T Call(int i)
                => null != Fun
                    ? Fun(i)
                    : IndexerDefaultImpl<T>(i);
        }
    }

    public class YourClass<T>
    {
        public T this[int i] => IndexerImpl.Specializer<T>.Call(i);
    }

如果需要传入实例对返回结果进行计算,可以增加一个参数:

    internal static class IndexerImpl //non-generic static helper class
    {
        private static T IndexerDefaultImpl<T>(int i, YourClass<T> yourClass) => default(T); //default implementation

        private static T IndexerImpl2<T>(int i, YourClass<T> yourClass) => default(T); //another implementation for short/int/long

        private static string IndexerForString<T>(int i, YourClass<T> yourClass) => (i * i).ToString(); //specialization for T=string
        private static DateTime IndexerForDateTime<T>(int i, YourClass<T> yourClass) => new DateTime(i * i * i); //specialization for T=DateTime

        static IndexerImpl() //install the specializations
        {
            Specializer<string>.Fun = IndexerForString;
            Specializer<DateTime>.Fun = IndexerForDateTime;

            Specializer<short>.Fun = IndexerImpl2;
            Specializer<int>.Fun = IndexerImpl2;
            Specializer<long>.Fun = IndexerImpl2;
        }

        internal static class Specializer<T> //specialization dispatcher
        {
            internal static Func<int, YourClass<T>, T> Fun;
            internal static T Call(int i, YourClass<T> yourClass)
                => null != Fun
                    ? Fun(i, yourClass)
                    : IndexerDefaultImpl(i, yourClass);
        }
    }

    public class YourClass<T>
    {
        public T this[int i] => IndexerImpl.Specializer<T>.Call(i, this);
    }

二、泛型方法的偏特化

偏特化也是差不多的做法,只不过帮助类变成了以不需要特化的类型构成的泛型类:

    internal static class GetValueImpl<R, S>
    {
        private static T DefImpl<T>(R r, S s) => default(T);
        private static int IntRet(R r, S s) => int.MaxValue;

        internal static class Specializer<T>
        {
            internal static Func<R, S, T> Fun;
            internal static T Call(R r, S s) => null != Fun ? Fun(r, s) : DefImpl<T>(r, s);
        }

        static GetValueImpl()
        {
            Specializer<int>.Fun = IntRet;
        }
    }

    public class TestClass
    {
        public T GetValue<R, S, T>(R r, S s) => GetValueImpl<R, S>.Specializer<T>.Call(r, s);
    }

以上代码片段中,被偏特化的是 GetValue 方法中的 T 类型参数,当 T=int 的时候,实际被调用的方法就是 GetValueImpl.IntRet 方法,其他情况是 GetValueImpl.DefImpl 方法。

三、泛型类的特化

泛型类的特化没有什么好的方法,只能采用继承特化类型泛型类的方式间接实现,并且将要特化处理的成员采用虚方法或者用 new 隐藏基类方法。

偏特化泛型类也可以采用差不多的方式实现。

具体做法可以参考 stackoverflow 上的这个答案:A: C# specialize generic class

收藏
评论区

相关推荐

Dart中的泛型、泛型方法、泛型类、泛型接口
一、Dart中的泛型 泛型方法 通俗理解:泛型就是解决 类 接口 方法的复用性、以及对不特定数据类型的支持(类型校验) 一般用   T   表示泛型 getData<T(T value){ return
C# 泛型特化
C# 泛型不是 C++ 的模板类,并不支持特化和偏特化,但是使用一些技巧可以在一定程度上达到相同的目的。 原文是 po 在 stackoverflow 上的一个回答:[A: Generic indexer overload specialization](https://www.oschina.net/action/GoToLink?url=https%3
C#泛型
现在的netcore 3.1和最新的.netframework8早已经没有当初那个被人诟病的ArrayList了,但很巧这玩意不得不说,因为它决定了C#团队痛改前非,抛弃过往重新上路,上一段ArrayList案例代码。 public class ArrayList { private object[]
C#非泛型集合和泛型集合的超级详解(转)
C# 泛型集合之非泛型集合类与泛型集合类的对应: ------------------------ ArrayList对应List HashTable对应Dictionary Queue对应Queue Stack对应Stack SortedList对应SortedList ###  转自(https://www.cnblogs.com/cheng
Java 泛型
命名类型参数 推荐的命名约定是使用大写的单个字母名称作为类型参数。这与 C++ 约定有所不同(参阅 附录 A:与 C++ 模板的比较),并反映了大多数泛型类将具有少量类型参数的假定。对于常见的泛型模式,推荐的名称是: K —— 键,比如映射的键。 V —— 值,比如 List 和 Set 的内容,或者 Map 中的值。 E
Java泛型的使用
### 泛型的定义: 泛型,就是允许在定义类、接口时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这个类型参数将在使用时(例如,继承或实现这个接口,用这个类型声明变量、创建对象时)确定(即传入实 际的类型参数,也称为类型实参)。 ### 泛型的引入背景: 集合容器类在设计阶段或声明阶段不能确定这个容器到底实际存储的是什么类型的对象
Java泛型详解
**引言** ------ Java泛型是jdk1.5中引入的一个新特性,泛型提供了编译时的类型检测机制,该机制允许程序员在编译时检测到非法的类型。 泛型是Java中一个非常重要的知识点,在Java集合类框架中泛型被广泛应用。本文我们将从零开始来看一下Java泛型的设计,将会涉及到通配符处理,以及让人苦恼的类型擦除。 **泛型基础** --------
java 泛型详解
对java的泛型特性的了解仅限于表面的浅浅一层,直到在学习设计模式时发现有不了解的用法,才想起详细的记录一下。 本文参考java 泛型详解、Java中的泛型方法、 java泛型详解 1\. 概述 泛型在java中有很重要的地位,在面向对象编程及各种设计模式中有非常广泛的应用。 什么是泛型?为什么要使用泛型? 泛型,即“参数化类型”。一提到参数,最熟
java泛型
一、实现机制 java泛型实现方法为类型擦除,基于这种方法实现的泛型称为伪泛型。 java泛型只在源代码中存在,在编译后的文件中替换为原生类型,并插入强制转换。 (真正的泛型是应该存在于源码、编译后文件、运行期) 二、擦除实例 源码: List<String> testList = new ArrayList<String>();
java泛型总结
###1. 特点, 好处 java1.5后出现 包含1.5版本 泛型的出现 解决程序的安全性 保证程序的一致安全机制 使用泛型 避免了类型的强制类型转换 代码就简单 数据类型只能是 应用类型 **不能使基本类型,且前后保持一致** 泛型的 定义格式: > 集合类<数据类型>变量 = new集合类<数据类型>(); ###2. 定义使用
20175209 《Java程序设计》第八周学习总结
20175209 《Java程序设计》第八周学习总结 ========================== ### 一、教材知识点总结 #### 1.泛型 1.泛型类声明: * 格式 `class People<E>` * People是泛型类名称 * E是泛型列表,可以是任何对象或接口,但不能是基本类型数据
20175209 《Java程序设计》第八周学习总结
20175209 《Java程序设计》第八周学习总结 ========================== ### 一、教材知识点总结 #### 1.泛型 1.泛型类声明: * 格式 `class People<E>` * People是泛型类名称 * E是泛型列表,可以是任何对象或接口,但不能是基本类型数据
Gson解析泛型
1、简单对象我们传入对象Class来将JSON字符串转为对象 private static <T> T fromJson(String result, Class<T> classOfT) { if (result == null) { return null; }
Thinking in java Chapter15 泛型
* 1 与C ++比较 * 2 简单泛型 泛型 类 * 3 泛型 接口 * 4 泛型 方法 * 5 匿名内部类 * 6 构建复杂模型 * 7 * 8 * 9 * 10 “泛型”意思就是:适用于许多许多的类型 <h2 id="1">1 与C++比较 </h2> ------------------------- C
TypeScript Generics(泛型)
软件工程的一个主要部分就是构建组件,构建的组件不仅需要具有明确的定义和统一的接口,同时也需要组件可复用。支持现有的数据类型和将来添加的数据类型的组件为大型软件系统的开发过程提供很好的灵活性。 在C#和Java中,可以使用"泛型"来创建可复用的组件,并且组件可支持多种数据类型。这样便可以让用户根据自己的数据类型来使用组件。 **泛型的简单案例** 首先,