循环引用这个报错太恶心了

实在不行自定义全局事件,两边拿到的引用只是GlobalEventManager之类的

let aa=tiemNode.getComponent(“XXX”)
//@ts-ignore
aa.bb()
//如果想要消除循环引用,那就只能通过接口的方式去消除了,目测ts还不大好实现,总之我没试过,试过后再回复

这种方式是我目前在用的,通过事件监听来解耦,但是目测不大舒服

事件推动的后期维护麻烦的很。

1赞

同感~~~

非继承导致的循环引用错误基本都是架构不合理
如果是多个继承类型引用同一模块导致循环引用就用我上面说的动态导入

肯定是继承导致的。
我说的情况属于,A继承R,R继承C,B也继承C,在B里面只是想在碰撞中通过other.getComponent(A)获取一个属性用来判断而已~

?? 显然是你记错了. 而且 import type 解决了类型提示的问题.


// manager.ts

import type {Item} from './item';
export const ITEM_COMP = 'xxx';

@ccclass
export class Manager extends Component
{
  some_method()
  {
     (<Item> this.node.children[0].getComponent(ITEM_COMP)).foo();
  }
}

// item.ts

import {ITEM_COMP, Manager} from './manager';

@ccclass(ITEM_COMP)
export class Item extends Component 
{
    foo() { Manager.instance.bar() } 
}

为啥你一直推荐用 import type? 每个方法都有合适和不合适的使用时机

用字符串作为 getCompoent 参数是给项目增加隐患,类名改了就获取不到,只有运行时才知道错误,而一些不常用的模块如果测试没测到就是隐藏 bug

你这纯粹是为了 import type 而 import type,根本没思考哪种更适合

首先, COMP_NAME 是一个 export const, 又不是 Magic string. 完全不影响重构和维护.
要说有什么缺点, 大概是重名冲突 (稍大的项目肯定是要加前缀的, 如 ‘cc.Button’, ‘cc.Label’ … )

其次, 编辑器只认 @ccclass(’ 里面的内容’), 根本不管你类名是什么 (如果 @ccclass(空), 编辑器认 文件名).

对~ 因为 getComponent(COMP_NAME) 根本不是问题.
typescript 支持 import type 很大程度就是为了解决循环引用问题, 简单容易理解, why not ?


总结

  • dynamic import: 把模块作为 延迟导入使用
  • import type: 只导入 ts 类型, 不产生运行时开销
  • 它们不是对立关系

你怕是自动忽略了什么,而且提出使用字符串来使用 getComponent 的,大部分都是新手所为

COMP_NAME 只是规避循环引用的一种办法而已, 它不影响你在别处直接用类名.
如果你很多地方都有循环引用, 所以觉得这是个问题, 那才是真的问题.

你怕是自动忽略了什么, 有什么绝对好与坏的东西么, 事实上, 引擎代码里就有不少 getComponent(“string”).

别强撑面子了

1. 我刚说完有合适不合适的

getComponent 使用字符串和类型对象的参数傻子都知道选什么

2. 自我矛盾

我说类名的确是不具体,我指的也是这个意思

1. 你能保证不修改 ccclass 装饰器参数传递的类型名?或者文件名?

2. 你能保证团队里的每个人都会在修改后去检查是否有使用 getComponent 接口(参数为字符串)获取这个类型并修改吗?

最后不管有没有循环引用,都应该避免使用字符串参数使用 getComponent,这才是我的想法

在我提醒后还没理解,属实把我给整笑了

论坛里面一堆为了面子能指鹿为马的,笑死了,承认自己错误像要杀了自己一样

来了, 来了, 他来了… 为什么论坛里的人都讨厌你, 没点数么?


回到正题:

?? 随便改啊, 会有问题 ? COMP_NAME 又不是魔法字符串, 明白么?
而且, 只有 mgr 里面需要 getComponent(COMP_NAME), 其他地方谁不让你用 getComponent(Item) 了么?

import {COMP_NAME} from ‘mgr’;

@cclass(COMP_NAME)
class Item {}


初衷没错, 为了容易维护, 少用魔法字符串.
可惜咱 不是魔法字符串 …只要没有违背你的初衷, 何必去坚持那些教条?

比较一下:

  • export const STRING = ‘xxx’;
  • export const CLASS = class {}

本质上是一样的. 只是一个是 ‘string’, 一个是 ‘function’,
你凭什么规定 ‘function’ 一定比 ‘string’ 更好 ?

只是对于 typescript 来说, 用 getComponent(class) 要 方便一点, 仅此而已.

咋到你这里还成了正治正确了? 还让别人 “认错”… 能不能不要这么幼稚?


还有一种情况, 也适合用 getComponent(string):

编译时剔除 (与 cc 引擎相似), 我们这样可以检测它是否存在, 有条件地决定一些 feature, 而不用 import 那个组件, 避免因此导致无法剔除, 或者变成 undefined:

//如果你剔除了 Button, 它就是 undefined 了, 你甚至无法确定是不是 bug...
//❌ error: getComponent: Type must be non-nil
this.getComponent(Button); 
//但你可以用:
this.getComponent('cc.Button') 

接下来 :rofl: :rofl:

事实上,觉得我说的对的人不会回复,而只有被我说中恼羞成怒的人才会一直回复导致你的印象是

又来 无中生有

请引用一下我的规定 ‘function’ 一定比 ‘string’ 更好

我之所以说为什么 getComponent 使用类型对象参数比字符串参数好,我上面已经说了,恼羞成怒的人自然不会看到,所以一直忽略我说的话

甚至为了合理而合理

我请问下正常人有几个会把项目里面所有 ccclass 装饰器字符串参数全部包装起来使用?

  • 包装
  • 未包装

0 投票者

自己诠释了什么叫无中生有. 谁跟你说过所有地方都这样写 ??

好的,既然不是所有地方,那么你是否承认使用 getComponent 字符串参数比类型对象参数维护困难? :rofl:

@ccclass(COMP_NAME) 请实例演示下如何就获取不到了.

前面没看懂我说的, 后面假模假样说自己 “也是这个意思” …真有意思.

“都应该” ? 我上面说了有的情形字符串更好, 这会儿装没看见?

你说的字符串维护困难的原因, 都是自以为是, 我 demo 是这么写的么?

我的 demo 一开始写法就没变, 单纯作为规避循环引用. 正常人会认为所有代码都这样写?

要按你的错误理解来维护, 肯定困难…

正常人用字符串: export const COMP_NAME = 'xxx'; 完事.

vs.

你用字符串: (自己说的)

  • 改个类名都要找到团队每个人所有的 getComponent, 确实困难.

  • 还打算把所有类改写成 @cclass(COMP_NAME), 勇气可嘉.


:arrow_up: 看出来了, 我说用来解决循环引用, 敢情你整个项目全是循环引用, 真是写得一手好代码 :+1:.

:arrow_up: 正常人谁需要干这些事, 没办法, 有人喜欢强行找茬呗.