public void TryDetach()
        {
            if (m_dataSource == null)
            {
                return;
            }

            if (Mode == BindMode.EVENT)
            {
                if (m_bindFunc == null || !BindTarget)
                {
                    return;
                }
                LuaBindingEventBase.UnbindEvent(BindTargetProp, BindTarget.gameObject, m_bindFunc);
                m_bindFunc?.Dispose();
                m_bindFunc = null;
                m_dataSource.Dispose();
                m_dataSource = null;
                return;
            }

            if (detach != null && (Mode == BindMode.ONE_WAY || Mode == BindMode.TWO_WAY))
            {
                detach(m_dataSource, m_expression ? GetExpressionKey() : Path, watchCallback);
                detach = null;
            }

            m_dataSource.Dispose();
            m_dataSource = null;

            if (BindTarget is LuaMVVMForEach forEach)
            {
                forEach.LuaArrayData = null;
            }

            if (m_propertyChangeCallback != null)
            {
                m_propertyChangeCallback.OnPropertyChanged -= OnPropertyChanged;
            }
        }
        public void Bind(LuaTable dataContext)
        {
            if (m_dataSource != null)
            {
                TryDetach();
            }

            object bindingValue = null;

            try {
                m_dataSource = dataContext;
                if (m_expression)
                {
                    var function = TempBindingExpressCache.GenerateTempFunction(ref Path);
                    using (var setupTempFunc = m_dataSource.GetInPath <LuaFunction>("setup_temp_getter")) {
                        bindingValue = setupTempFunc.Func <string, LuaFunction, object>(GetExpressionKey(), function);
                    }
                }
                else
                {
                    if (m_dataSource == null)
                    {
                        return;
                    }

                    if (Mode == BindMode.EVENT)
                    {
                        m_bindFunc = dataContext.GetInPath <LuaFunction>(Path);
                        Assert.IsNotNull(m_bindFunc);
                        LuaBindingEventBase.BindEvent(BindTargetProp, BindTarget.gameObject, m_bindFunc);
                        return;
                    }

                    bindingValue = dataContext.GetInPath <object>(Path);
                }
            }
            catch (Exception e) {
                Debug.LogException(e);
            }


            if (bindingValue == null)
            {
                Debug.LogWarning($"Not found value in path {Path}");
                return;
            }

            switch (Mode)
            {
            case BindMode.ONE_WAY:
            case BindMode.TWO_WAY:
            case BindMode.ONE_TIME: {
                if (Mode == BindMode.ONE_WAY || Mode == BindMode.TWO_WAY)
                {
                    var watch = dataContext.GetInPath <WatchLuaProperty>("watch");
                    watch(dataContext, m_expression ? GetExpressionKey() : Path, watchCallback, m_expression);
                    detach = dataContext.Get <DetachLuaProperty>("detach");
                    Assert.IsNotNull(detach);

                    if (Mode == BindMode.TWO_WAY)
                    {
                        if (m_expression)
                        {
                            Debug.LogError("express type can not to source");
                        }
                        else
                        {
                            m_propertyChangeCallback = BindTarget.GetComponent <IUnityPropertyChanged>();
                            m_propertyChangeCallback.OnPropertyChanged += OnPropertyChanged;
                        }
                    }
                }

                SetPropertyValue(bindingValue);

                break;
            }

            case BindMode.ONE_WAY_TO_SOURCE:
                if (m_expression)
                {
                    Debug.LogError("express type can not to source");
                    return;
                }

                m_propertyChangeCallback = BindTarget.GetComponent <IUnityPropertyChanged>();
                dataContext.SetInPath(Path, m_propertyChangeCallback.ProvideCurrentValue());
                m_propertyChangeCallback.OnPropertyChanged += OnPropertyChanged;
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }