通过c#反射初始化系统

在项目中,特别是ui系统,经常需要做一个ui系统的管理和ui系统初始化,以及ui系统销毁等情况。

一般有两种方式来管理ui系统

1.每加一个系统就在uimanager中加一个引用。

比如(伪代码)

UIManager

{

uis.add(ASystemClass)

}

类似这样做,然后用uis来统一管理ui

优点:这样写很直观,在一个ui系统做完,可以自己管理ui系统初始化顺序

缺点:每加一个系统都需要在这里修改代码,对于开发者的维护成本比较高

 

2.用c#反射自动获取相关的类来管理

首先我们会有一个获取属性的基类

public class AttributeHandler<T>
{
    // 消息处理表
    protected Dictionary<int, T> mMsgHandlers = new Dictionary<int, T>();
    protected void RegisterAttribute(Type attributeType, Assembly InAssembly)
    {
        ClassEnumerator Enumerator = new ClassEnumerator(
            attributeType,
            null,
            InAssembly
            );

        var Iter = Enumerator.results.GetEnumerator();

        while (Iter.MoveNext())
        {
            var ClassType = Iter.Current;
            var attribute = ClassType.GetCustomAttribute(attributeType, true) as HandlerAttribute;

            if (attribute != null)
            {
                RegisterMsgHandler(
                    attribute.ID,
                    ClassType
                    );
            }
        }
    }

    /// <summary>
    /// 注册消息处理
    /// </summary>
    /// <param name="cmdID"></param>
    /// <param name="handler"></param>
    protected void RegisterMsgHandler(int cmdID, Type handler)
    {
        if (mMsgHandlers.ContainsKey(cmdID))
        {
            DebugHelper.LogError(string.Format("重复的事件监听, id={0}", cmdID));
            return;
        }
        Type[] pt = new Type[0];
        object[] pv = { };
        //通过类型数组获取对应的类型的构造器
        ConstructorInfo con = handler.GetConstructor(pt);
        T conInfo = (T)(con.Invoke(pv));
        //DebugHelper.Log("CmdID Add : " + cmdID);
        mMsgHandlers.Add(cmdID, conInfo);
    }

}

当然我们有一个ClassEnumerator是方便我们枚举出我们所有相关的类的

public class ClassEnumerator
{
    protected List<Type> Results = new List<Type>();

    public List<Type> results { get { return Results; } }

    private Type AttributeType;
    private Type InterfaceType;

    public ClassEnumerator(
        Type InAttributeType,
        Type InInterfaceType,
        Assembly InAssembly,
        bool bIgnoreAbstract = true,
        bool bInheritAttribute = false,
        bool bShouldCrossAssembly = false
        )
    {
        AttributeType = InAttributeType;
        InterfaceType = InInterfaceType;

        try
        {
            if (bShouldCrossAssembly)
            {
                Assembly[] Assemblys = AppDomain.CurrentDomain.GetAssemblies();

                if (Assemblys != null)
                {
                    for (int i = 0; i < Assemblys.Length; ++i)
                    {
                        var a = Assemblys[i];
                        CheckInAssembly(a, bIgnoreAbstract, bInheritAttribute);
                    }
                }
            }
            else
            {
                CheckInAssembly(InAssembly, bIgnoreAbstract, bInheritAttribute);
            }
        }
        catch (Exception e)
        {
            DebugHelper.LogError("Error in enumerate classes :" + e.Message);
        }
    }

    protected void CheckInAssembly(
        Assembly InAssembly,
        bool bInIgnoreAbstract,
        bool bInInheritAttribute
        )
    {
        Type[] Types = InAssembly.GetTypes();

        if (Types != null)
        {
            for (int i = 0; i < Types.Length; ++i)
            {
                var t = Types[i];

                // test if it is implement from this interface
                if (InterfaceType == null || InterfaceType.IsAssignableFrom(t))
                {
                    // check if it is abstract
                    if (!bInIgnoreAbstract || (bInIgnoreAbstract && !t.IsAbstract))
                    {
                        // check if it have this attribute
                        if (t.GetCustomAttributes(AttributeType, bInInheritAttribute).Length > 0)
                        {
                            if (t.IsClass)
                            {
                                Results.Add(t);
                            }

                            // Debug.Log("Found Type:" + t.FullName + " : " + a.GetName());
                        }
                    }
                }
            }
        }
    }
}

然后我们可以有一个uimanager来初始化反射后的数据

public class SceneManager : AttributeHandler<BaseScene>
    {
        void IScene.Init()
        {
            RegisterAttribute(typeof(SceneHandlerAttribute), typeof(BaseScene).Assembly);

        }


        protected BaseScene ReflectionScene(ESceneName ePanelType, ref SceneHandlerAttribute attribute)
        {
            BaseScene basePanel = null;
            mMsgHandlers.TryGetValue((int)ePanelType, out basePanel);
            
            attribute = basePanel.GetType().GetCustomAttribute(typeof(SceneHandlerAttribute), true) as SceneHandlerAttribute;

            return basePanel;
        }

    }

其中BaseScene就是我们的ui系统基类

我们在app初始化的勾朑调用基类的RegisterAttribute来获取所有相关的ui系统。这样就能通过反射来管理所有ui系统了。

其中ReflectionScene方法是用于获取当前的ui系统的。这其中有一个没有说的枚举是ESceneName ,这里枚举出来的是所有ui系统。

类似这样

 public enum ESceneName
{
            None = -1,
            AppLoginScene,          //登陆 scene
            MainScene,              //Main scene
            MapScene,               //地图Scene
            PersonAgeScene,         //个人Scene
}

然后我需要既然有需要反射的class,那么我们就需要定义我们的反射属性才行,也就是上面的SceneHandlerAttribute

public class HandlerAttribute :
    Attribute,
    IIdentifierAttribute<int>
{
    public int mMessageID;

    public int ID { get { return mMessageID; } }

    public HandlerAttribute(int InMessageID)
    {
        mMessageID = InMessageID;
    }
}

public class SceneHandlerAttribute :
    HandlerAttribute,
    IIdentifierAttribute<int>
{
    public string mPackageURL;

    public string mComponentName;
    
    public string PackageURL { get { return mPackageURL; } }
    public string ComponentName { get { return mComponentName; } }
    
    public SceneHandlerAttribute(int InMessageID, string PackageURL, string ComponentName):base(InMessageID)
    {
        mMessageID = InMessageID;
        mPackageURL = PackageURL;
        mComponentName = ComponentName;
    }
}

这样反射才知道要拿什么还有怎么从其他class重反射相关参数过管理类来。

最后就是我们真正需要用ui系统反射的地方

[SceneHandlerAttribute((int)SceneData.ESceneName.MainScene, "HomePackage", "Main")]
public class MainScene : BaseScene
{
}

类似这样,就会把该类放入uimanager中管理以及传入参数

mMessageID = SceneData.ESceneName.MainScene;
mPackageURL = “HomePackage”;
mComponentName = “Main”;

 

优点:我们不需要手动加代码到uimanager了,管理成本低了很多。uimanager统一管理,需要加[SceneHandlerAttribute((int)SceneData.ESceneName.MainScene, "HomePackage", "Main")]这样的头部就好了

缺点:

1.没有顺序,顺序完全是按照dll获取到的class顺序走的,所以ui系统中在初始化时不能有顺序依赖。

2.在初始化的时候因为要反射所有类,所以会有一个搜索过程,同一个工程中的类越多就搜索越久。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值