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

科技资讯 投稿 6400 0 评论

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

概述

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

需求示例

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

输出:

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

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 (Rins;
                }
            }
        }

        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#可以保存类型信息到运行期,通过运行期分析类型信息创建对象实现静态多态。

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

编程笔记 » C#模拟C++模板特化对类型的值的支持

赞同 (35) or 分享 (0)
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽