C#模拟C++模板特化对类型的值的支持

这篇具有很好参考价值的文章主要介绍了C#模拟C++模板特化对类型的值的支持。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

概述

C++的模板相比于C#的泛型,有很多地方都更加的灵活(虽然代价是降低了编译速度),比如C++支持变长参数模板、支持枚举、int等类型的值作为模板参数。
C++支持枚举、int等类型的值作为模板参数,为C++的静态多态编程提供了很好的帮助,比如根据枚举值编译期确定某个对象的行为策略等(下文举例)。但是C#对这些都是不支持,但是C#天然支持反射,这种需求可以使用反射特性来实现。

需求示例

定义枚举 enum EPlant {Tree, Flower},根据枚举的值打印Tree,Flower字符串。注意,这里的应用场景是编译器时的多态,即编码时便确定使用的对象的类型。

C++的实现

上述的例子,C++的语法支持可以天然的实现,如下:

#include <iostream>

enum class EPlant
{
    Tree = 0,
    Flower,
};

template<EPlant ...Args>
class PrintPlant
{
    
};

template<>
class PrintPlant<>
{
public:
    void Print()
    {
        std::cout << "Plant" << std::endl;;
    }
};

template<>
class PrintPlant<EPlant::Tree>
{
public: 
    void Print()
    {
        std::cout << "Tree" << std::endl;;
    }
};

template<>
class PrintPlant<EPlant::Flower>
{
public:
    void Print()
    {
        std::cout << "Flower" << std::endl;
    }
};

int main()
{
    auto plant = new PrintPlant<>();
    plant->Print();
    auto flower = new PrintPlant<EPlant::Flower>();
    flower->Print();
    auto tree = new PrintPlant<EPlant::Tree>();
    tree->Print();
}

输出:
C#模拟C++模板特化对类型的值的支持

  • template<EPlant ...Args> 这里使用变长参数模板,来支持没有传入模板参数的情况,特化类型Print函数打印"plant"
  • template<> class PrintPlant<EPlant::Tree> 模板特化的类型,在main里使用了new PrintPlant<EPlant::Tree>();语句创建该类型的对象。该对象打印"Tree"。

C# 实现

C#的模板不支持枚举的值作为模板参数,使用反射进行模拟。

using System;
using System.Reflection;
using System.Collections.Generic;

[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ABTEX : Attribute
{
    public object key;

    public ABTEX(object k)
    {
        key = k;
    }
}

public class TEX
{
    static Dictionary<Type, Dictionary<Type, Dictionary<string, object>>> dict;
    public static void Init(Type[] types)
    {
        dict = new();
        foreach (var t in types)
        {
            var ABTEX = t.GetCustomAttribute<ABTEX>();
            var bt = t.BaseType;
            if (ABTEX != null && bt != null)
            {
                AddInst(t, bt, ABTEX.key);
            }
        }
    }

    static string FmtKey(object key)
    {
        return $"{key}";
    }

    static void AddInst(Type ty, Type bt, object key)
    {
        if (!dict.ContainsKey(bt))
        {
            dict[bt] = new();
        }

        var kt = key.GetType();
        string k = FmtKey(key);

        if (!dict[bt].ContainsKey(kt))
        {
            dict[bt][kt] = new();
        }

        dict[bt][kt][k] = Activator.CreateInstance(ty);
    }

    static public R T<R>(object key)
    {
        if (dict.TryGetValue(typeof(R), out Dictionary<Type, Dictionary<string, object>> dbt))
        {
            var kt = key.GetType();
            string k = FmtKey(key);
            if (dbt.TryGetValue(kt, out Dictionary<string, object> kbt))
            {
                if (kbt.TryGetValue(k, out object ins))
                {
                    return (R)ins;
                }
            }
        }

        return default(R);
    }
}

public enum EPlant : int
{
    None = 0,
    Tree,
    Flower,
}

public class APrintPlant
{
    public virtual void Print()
    {
        Console.WriteLine("Plant");
    }
}

[ABTEX(EPlant.Tree)]
public class PrintTree : APrintPlant
{
    public override void Print()
    {
        Console.WriteLine("Tree");
    }
}

[ABTEX(EPlant.Flower)]
public class PrintFlower : APrintPlant
{
    public override void Print()
    {
        Console.WriteLine("Flower");
    }
}

class Program
{
    static void Main(string[] args)
    {
        var all = Assembly.GetExecutingAssembly().GetTypes();
        TEX.Init(all);
        TEX.T<APrintPlant>(EPlant.Tree).Print();
        TEX.T<APrintPlant>(EPlant.Flower).Print();
    }
}

输出:
C#模拟C++模板特化对类型的值的支持
C#可以保存类型信息到运行期,通过运行期分析类型信息创建对象实现静态多态。文章来源地址https://www.toymoban.com/news/detail-416457.html

  • TEX类分析传入的所有类型,筛选父类和ABTEX特性,使用父类型,ABTEX的key的类型和值来索引该类型。(这里索引是实例对象,有需求的话可以保存类型Type,使用类型通过反射创建对象)
  • ABTEX标记需要反射分析的类型,并且标记key。
  • Main入口获取当前程序集下所有的类型信息,初始化TEX
  • 通过TEX.T<抽象类>(key).Func 调用方法(注意: 这里使用这些类作为纯函数的类,故使用类似单例的用法。也可以在初始化记录类型,通过反射创建多个实例。)

到了这里,关于C#模拟C++模板特化对类型的值的支持的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++学习】模板进阶——非类型模板参数 | 模板的特化 | 分离编译

    🐱作者:一只大喵咪1201 🐱专栏:《C++学习》 🔥格言: 你只管努力,剩下的交给时间! 模板我们之前一直都在使用,尤其是在模拟STL容器的时候,可以说,模板给类增加了更多的可能性,是C++最重要的部分之一。下面本喵来更深入的讲解一下模板。 在上面代码中,创建了

    2023年04月13日
    浏览(35)
  • 【C++】模板进阶—非类型模板参数、模板特化及模板的分离编译

    🚀 作者简介:一名在后端领域学习,并渴望能够学有所成的追梦人。 🚁 个人主页:不 良 🔥 系列专栏:🛸C++  🛹Linux 📕 学习格言:博观而约取,厚积而薄发 🌹 欢迎进来的小伙伴,如果小伙伴们在学习的过程中,发现有需要纠正的地方,烦请指正,希望能够与诸君一同

    2024年02月16日
    浏览(36)
  • 【C++初阶(十)】C++模板(进阶) ---非类型模板参数、模板的特化以及模板的分离编译

    本专栏内容为:C++学习专栏,分为初阶和进阶两部分。 通过本专栏的深入学习,你可以了解并掌握C++。 💓博主csdn个人主页:小小unicorn ⏩专栏分类:C++ 🚚代码仓库:小小unicorn的代码仓库🚚 🌹🌹🌹关注我带你学习编程知识 模板参数可分为类型形参和非类型形参。 类型形

    2024年01月18日
    浏览(36)
  • 【C++】模板+模板特化

    铁汁们,今天给大家分享一篇模板+模板特化,来吧,开造⛳️ 定义:编写跟具体类型无关的通用代码,是实现代码复用的一种手段。模板是泛型编程的基础。 问:如何实现一个通用的swap函数? 答:写成函数模板,不能在函数重载了。原因:代码复用率低,重载的函数仅是

    2024年03月24日
    浏览(35)
  • C++类模板的特化(三)

    本文主要介绍类模板的特化、局部特化和缺省模板实参; 类模板的特化(Class Template Specialization)是指为特定的模板参数提供自定义实现的过程。通过特化,我们可以针对某些特定的类型或条件提供不同的行为或实现; 如果需要特化一个类模板,需要特化该模板中的所有成员

    2024年02月11日
    浏览(44)
  • C++标准模板(STL)- 类型支持 (数值极限,C 数值极限接口)

    参阅 std::numeric_limits 接口 定义于头文件 cstdint PTRDIFF_MIN (C++11) std::ptrdiff_t 类型对象的最小值 (宏常量) PTRDIFF_MAX (C++11) std::ptrdiff_t 类型对象的最大值 (宏常量) SIZE_MAX (C++11) std::size_t 类型对象的最大值 (宏常量) SIG_ATOMIC_MIN (C++11) std::sig_atomic_t 类型对象的最小值 (宏常量) SIG_ATOMIC_

    2024年02月07日
    浏览(40)
  • C#的值类型和引用类型

    在C#中,数据类型可以分为值类型(Value Types)和引用类型(Reference Types)两种。下面是对它们的详细解释和示例说明: 值类型(Value Types): 值类型变量直接包含它们的数据,存储在栈上。 值类型包括整数类型(如int、byte、char)、浮点类型(如float、double)、布尔类型(如

    2024年02月15日
    浏览(43)
  • C++标准模板(STL)- 类型支持 (类型特性,is_union,is_class,is_function)

    类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。 试图特化定义于 type_traits 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。 定义于type_traits头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实

    2024年02月06日
    浏览(51)
  • 重温C#中的值类型和引用类型

    在C#中,数据类型分为 值类型 和 引用类型 两种。 引用类型变量存储的是数据的引用,数据存储在数据堆中,而值类型变量直接存储数据。对于引用类型,两个变量可以引用同一个对象。因此,对一个变量的操作可能会影响另一个变量引用的对象。对于值类型,每个变量都有

    2024年02月15日
    浏览(47)
  • C++标准模板(STL)- 类型支持 (类型特性,is_member_object_pointer,is_member_function_pointer)

    类型特性定义一个编译时基于模板的结构,以查询或修改类型的属性。 试图特化定义于 type_traits 头文件的模板导致未定义行为,除了 std::common_type 可依照其所描述特化。 定义于type_traits头文件的模板可以用不完整类型实例化,除非另外有指定,尽管通常禁止以不完整类型实

    2024年02月08日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包