本篇文章介绍如何实现如下代码的链式编程:

this.Position(Vector3.one)
.LocalScale(1.0f)
.Rotation(Quaternion.identity);

以上代码中,this 为 MonoBehaviour 类型的对象。

如何实现?

通过上篇文章介绍的 return this + 静态扩展很容易做到,实现代码如下所示:

        public static MonoBehaviour Position(this MonoBehaviour selfBehaviour, Vector3 position)
{
selfBehaviour.transform.position = position;
return selfBehaviour;
} public static MonoBehaviour LocalScale(this MonoBehaviour selfBehaviour, float xyz)
{
selfBehaviour.transform.localScale = Vector3.one * xyz;
return selfBehaviour;
} public static MonoBehaviour Rotation(this MonoBehaviour selfBehaviour, Quaternion rotation)
{
selfBehaviour.transform.rotation = rotation;
return selfBehaviour;
}

很容易实现对吧?但是这样有个问题,由于静态扩展方法返回的是 MonoBehaviour 类而不是this所属的类型,所以接下来链式方法中只能使用 MonoBehaviour 的方法。不能像如下方式使用。

            this.Position(Vector3.one)
.LocalScale(1.0f)
.Rotation(Quaternion.identity)
.DoSomething();

以上代码中,this 为 MonoBehaviour 类型的对象。

如何解决这个问题呢?答案是引入泛型。

引入泛型

实现代码如下所示:

        public static T Position<T>(this T selfBehaviour, Vector3 position) where T : MonoBehaviour
{
selfBehaviour.transform.position = position;
return selfBehaviour;
} public static T LocalScale<T>(this T selfBehaviour, float xyz) where T : MonoBehaviour
{
selfBehaviour.transform.localScale = Vector3.one * xyz;
return selfBehaviour;
} public static T Rotation<T>(this T selfBehaviour, Quaternion rotation) where T : MonoBehaviour
{
selfBehaviour.transform.rotation = rotation;
return selfBehaviour;
}

实现很简单,只是把之前代码中的 MonoBehaivour 改成泛型T,然后增加一个约束: where T : MonoBehaviour。表示这个泛型一定要继承自 MonoBehaviour。这样之前例子中的this可以使用MonoBehaviour 之外的方法实现链式编程了。

进一步完善

不只是自己实现的 MonoBehaviour 脚本像 UGUI 的 Image 等都要支持 transform 的链式编程。那么就要找到transfom 到底是哪个类?最后找到了如下代码。

namespace UnityEngine
{
/// <summary>
/// <para>Base class for everything attached to GameObjects.</para>
/// </summary>
[RequiredByNativeCode]
public class Component : Object
{
/// <summary>
/// <para>The Transform attached to this GameObject.</para>
/// </summary>
public extern Transform transform { [MethodImpl(MethodImplOptions.InternalCall)] get; }
...

最终定位到,transform 是 Component 的属性器。 所以可以将之前的实现改为如下代码:

        public static T Position<T>(this T selfComponent, Vector3 position) where T : Component
{
selfComponent.transform.position = position;
return selfComponent;
} public static T LocalScale<T>(this T selfComponent, float xyz) where T : Component
{
selfComponent.transform.localScale = Vector3.one * xyz;
return selfComponent;
} public static T Rotation<T>(this T selfComponent, Quaternion rotation) where T : Component
{
selfComponent.transform.rotation = rotation;
return selfComponent;
}

通过此种方式实现 Graphfic,Component 等类,最后可以实现如下方式的链式编程。

Image image = null;

image.LocalPosition(Vector3.back)
.ColorAlpha(0.0f)
.Hide();

当然,去查看一个属性到底是哪个类实现的这个过程也是一个很好的学习方式 : ) ,有很多类都可以实现链式编程,不过剩下的要靠大家自己了,当然也可以参考 QFramework 里的实现方式,不过 QFramework 也只是对笔者常用的类进行了实现。

OK,本篇介绍到这里。

转载请注明地址:凉鞋的笔记:liangxiegame.com

更多内容

Unity 游戏框架搭建 (十八) 静态扩展 + 泛型实现transform的链式编程的更多相关文章

  1. Unity 游戏框架搭建 (十) QFramework v0.0.2小结

    从框架搭建系列的第一篇文章开始到现在有四个多月时间了,这段时间对自己来说有很多的收获,好多小伙伴和前辈不管是在评论区还是私下里给出的建议非常有参考性,在此先谢过各位. 说到是一篇小节,先列出框架的概要 ...

  2. Unity 游戏框架搭建 (十六) v0.0.1 架构调整

    背景: 前段时间用Xamarin.OSX开发一些工具,遇到了两个问题. QFramework的大部分的类耦合了Unity的API,这样导致不能在其他CLR平台使用QFramework. QFramew ...

  3. Unity 游戏框架搭建 (十五) 优雅的QChain (零)

    加班加了三个月终于喘了口气,博客很久没有更新了,这段期间框架加了很多Feature,大部分不太稳定,这些Feature中实现起来比较简单而且用的比较稳定的就是链式编程支持了. 什么是链式编程? 我想大 ...

  4. Unity 游戏框架搭建 2019 (八) 关于导出 UnityPackage 功能的小结

    导出 UnityPackage 功能到这里要告一段落了,相信认真看的童鞋都有收获.笔者在写教程之前纠结了很久.到底是先给出一坨工具代码,然后再逐个讲解比较好,还是一篇一个知识点比较好.后来想通了.工具 ...

  5. Unity 游戏框架搭建 (十九) 简易对象池

    在Unity中我们经常会用到对象池,使用对象池无非就是解决两个问题: 一是减少new时候寻址造成的消耗,该消耗的原因是内存碎片. 二是减少Object.Instantiate时内部进行序列化和反序列化 ...

  6. Unity 游戏框架搭建 (十四) 优雅的QSignleton(零) QuickStart

      好久不见 !之前想着让各位直接用QFramework,但是后来想想,如果正在进行的项目直接使用QFramework,这样风险太高了,要改的代码太多,所以打算陆续独立出来一些工具和模块,允许各位一个 ...

  7. Unity 游戏框架搭建 (十二) 简易AssetBundle打包工具(二)

    上篇文章中实现了基本的打包功能,在这篇我们来解决不同平台打AB包的问题. 本篇文章的核心api还是: BuildPipeline.BuildAssetBundles (outPath, 0, Edit ...

  8. Unity 游戏框架搭建 2018 (一) 架构、框架与 QFramework 简介

    约定 还记得上版本的第二十四篇的约定嘛?现在出来履行啦~ 为什么要重制? 之前写的专栏都是按照心情写的,在最初的时候笔者什么都不懂,而且文章的发布是按照很随性的一个顺序.结果就是说,大家都看完了,都还 ...

  9. Unity 游戏框架搭建 (十三) 无需继承的单例的模板

    之前的文章中介绍的Unity 游戏框架搭建 (二) 单例的模板和Unity 游戏框架搭建 (三) MonoBehaviour单例的模板有一些问题. 存在的问题: 只要继承了单例的模板就无法再继承其他的 ...

随机推荐

  1. [转]Shared——Javascript中的call详解

    call( ) 一.call的使用 call 方法第一个参数是作为函数上下文的对象,第二个参数是一个参数列表. var obj = { name: 'J' } function func(p1, p2 ...

  2. ajax接收flask传递的json数据

    from flask import Flask, request import json app = Flask(__name__) @app.route('/') def func(): res = ...

  3. csharp: datagridview Convert csv file

    /// <summary> /// 保存文件 /// 涂聚文 /// 2014-08-29 /// Geovin Du /// </summary> /// <param ...

  4. Eclipse常用操作

    一 Eclipse常用快捷键 ctrl+Q:跳到最后一次编辑处. ctrl+F:在当前文件中查找并替换. ctrl+T:查看类的继承关系. alt+左箭头:返回到光标的上一个位置. alt+右箭头:前 ...

  5. numpy用法介绍-未完待续

    简介 NumPy(Numerical Python简称) 是高性能科学计算和数据分析的基础包 为什么使用? 标准安装的Python中用列表(list)保存一组值,可以用来当作数组使用,不过由于列表的元 ...

  6. recvfrom WSAEFAULT 10014 的错误记录

    在使用 recvfrom 时一直没报错, 像这样 recvfrom(sock, Data, , (sockaddr*)&server_addr, &send_size) 当我看见百度百 ...

  7. mongodb学习总结

    安装mongodb: 1.下载服务器最新稳定版本(选择偶数号的版本号),mongodb的版本管理偶数号为稳定版,奇数号为开发版. 2.安装时默认安装在c盘,可以选择自定义选项来改变安装路径. 3.安装 ...

  8. LeetCode-Subsets ZZ

    LeetCode:Subsets Given a set of distinct integers, S, return all possible subsets. Note: Elements in ...

  9. ignore_user_abort函数制定计划任务

    PHP中的ignore_user_abort函数是当用户关掉终端后脚本不停止仍然在执行,可以用它来实现计划任务与持续进程,下面会通过实例讨论ignore_user_abort()函数的作用与用法.   ...

  10. 【深入理解JAVA虚拟机】第二部分.内存自动管理机制.4.JVM工具

    1.概述 工具作用:性能监控与故障处理 工作原理:分析数据 数据包含:运行日志. 异常堆栈. GC日志. 线程快照(threaddump/javacore文件). 堆转储快照(heapdump/hpr ...