collectgarbage("setpause", 50)
collectgarbage("setstepmul", 200)

function dummycall()
end

local function get_basic_type_func()
    return function(v)
        return v
    end
end

Slua = Slua or {out = {}}
__cs2lua_out = Slua.out
__cs2lua_nil = {}

System = System or {}
System.Boolean = System.Boolean or get_basic_type_func()
System.SByte = System.SByte or get_basic_type_func()
System.Byte = System.Byte or get_basic_type_func()
System.Char = System.Char or get_basic_type_func()
System.Int16 = System.Int16 or get_basic_type_func()
System.Int32 = System.Int32 or get_basic_type_func()
System.Int64 = System.Int64 or get_basic_type_func()
System.UInt16 = System.UInt16 or get_basic_type_func()
System.UInt32 = System.UInt32 or get_basic_type_func()
System.UInt64 = System.UInt64 or get_basic_type_func()
System.Single = System.Single or get_basic_type_func()
System.Double = System.Double or get_basic_type_func()
System.String = System.String or get_basic_type_func()
System.Collections = System.Collections or {}
System.Collections.Generic = System.Collections.Generic or {}
System.Collections.Generic.List_T = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.List_T",
    __cs2lua_typename = "List"
}
System.Collections.Generic.Queue_T = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.Queue_T",
    __cs2lua_typename = "Queue"
}
System.Collections.Generic.Stack_T = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.Stack_T",
    __cs2lua_typename = "Stack"
}
System.Collections.Generic.Dictionary_TKey_TValue = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.Dictionary_TKey_TValue",
    __cs2lua_typename = "Dictionary"
}
System.Collections.Generic.HashSet_T = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.HashSet_T",
    __cs2lua_typename = "HashSet"
}
System.Collections.Generic.KeyValuePair_TKey_TValue = {
    __cs2lua_defined = true,
    __cs2lua_fullname = "System.Collections.Generic.KeyValuePair_TKey_TValue",
    __cs2lua_typename = "KeyValuePair"
}
System.Array = System.Array or {}
System.Nullable_T = System.Nullable_T or {}

System.Collections.Generic.MyDictionary_TKey_TValue = System.Collections.Generic.Dictionary_TKey_TValue or {}

System.Linq = System.Linq or {}
System.Linq.Enumerable = System.Linq.Enumerable or {}

Cs2LuaList_T = Cs2LuaList_T or {}
Cs2LuaIntDictionary_TValue = Cs2LuaIntDictionary_TValue or {}
Cs2LuaStringDictionary_TValue = Cs2LuaStringDictionary_TValue or {}

__cs2lua_special_integer_operators = {"/", "%", "+", "-", "*", "<<", ">>", "&", "|", "^", "~"}
__cs2lua_div = 0
__cs2lua_mod = 1
__cs2lua_add = 2
__cs2lua_sub = 3
__cs2lua_mul = 4
__cs2lua_lshift = 5
__cs2lua_rshift = 6
__cs2lua_bitand = 7
__cs2lua_bitor = 8
__cs2lua_bitxor = 9
__cs2lua_bitnot = 10

SymbolKind = {
    Alias = 0,
    ArrayType = 1,
    Assembly = 2,
    DynamicType = 3,
    ErrorType = 4,
    Event = 5,
    Field = 6,
    Label = 7,
    Local = 8,
    Method = 9,
    NetModule = 10,
    NamedType = 11,
    Namespace = 12,
    Parameter = 13,
    PointerType = 14,
    Property = 15,
    RangeVariable = 16,
    TypeParameter = 17,
    Preprocessing = 18,
    Discard = 19
}

TypeKind = {
    Unknown = 0,
    Array = 1,
    Class = 2,
    Delegate = 3,
    Dynamic = 4,
    Enum = 5,
    Error = 6,
    Interface = 7,
    Module = 8,
    Pointer = 9,
    Struct = 10,
    Structure = 10,
    TypeParameter = 11,
    Submission = 12
}

MethodKind = {
    AnonymousFunction = 0,
    LambdaMethod = 0,
    Constructor = 1,
    Conversion = 2,
    DelegateInvoke = 3,
    Destructor = 4,
    EventAdd = 5,
    EventRaise = 6,
    EventRemove = 7,
    ExplicitInterfaceImplementation = 8,
    UserDefinedOperator = 9,
    Ordinary = 10,
    PropertyGet = 11,
    PropertySet = 12,
    ReducedExtension = 13,
    StaticConstructor = 14,
    SharedConstructor = 14,
    BuiltinOperator = 15,
    DeclareMethod = 16,
    LocalFunction = 17
}

OperationKind = {
	None = 0,
	Invalid = 1,
	Block = 2,
	VariableDeclarationGroup = 3,
	Switch = 4,
	Loop = 5,
	Labeled = 6,
	Branch = 7,
	Empty = 8,
	Return = 9,
	YieldBreak = 10,
	Lock = 11,
	Try = 12,
	Using = 13,
	YieldReturn = 14,
	ExpressionStatement = 0xF,
	LocalFunction = 0x10,
	Stop = 17,
	End = 18,
	RaiseEvent = 19,
	Literal = 20,
	Conversion = 21,
	Invocation = 22,
	ArrayElementReference = 23,
	LocalReference = 24,
	ParameterReference = 25,
	FieldReference = 26,
	MethodReference = 27,
	PropertyReference = 28,
	EventReference = 30,
	UnaryOperator = 0x1F,
	BinaryOperator = 0x20,
	Conditional = 33,
	Coalesce = 34,
	AnonymousFunction = 35,
	ObjectCreation = 36,
	TypeParameterObjectCreation = 37,
	ArrayCreation = 38,
	InstanceReference = 39,
	IsType = 40,
	Await = 41,
	SimpleAssignment = 42,
	CompoundAssignment = 43,
	Parenthesized = 44,
	EventAssignment = 45,
	ConditionalAccess = 46,
	ConditionalAccessInstance = 47,
	InterpolatedString = 48,
	AnonymousObjectCreation = 49,
	ObjectOrCollectionInitializer = 50,
	MemberInitializer = 51,
	CollectionElementInitializer = 52,
	NameOf = 53,
	Tuple = 54,
	DynamicObjectCreation = 55,
	DynamicMemberReference = 56,
	DynamicInvocation = 57,
	DynamicIndexerAccess = 58,
	TranslatedQuery = 59,
	DelegateCreation = 60,
	DefaultValue = 61,
	TypeOf = 62,
	SizeOf = 0x3F,
	AddressOf = 0x40,
	IsPattern = 65,
	Increment = 66,
	Throw = 67,
	Decrement = 68,
	DeconstructionAssignment = 69,
	DeclarationExpression = 70,
	OmittedArgument = 71,
	FieldInitializer = 72,
	VariableInitializer = 73,
	PropertyInitializer = 74,
	ParameterInitializer = 75,
	ArrayInitializer = 76,
	VariableDeclarator = 77,
	VariableDeclaration = 78,
	Argument = 79,
	CatchClause = 80,
	SwitchCase = 81,
	CaseClause = 82,
	InterpolatedStringText = 83,
	Interpolation = 84,
	ConstantPattern = 85,
	DeclarationPattern = 86,
	TupleBinaryOperator = 87,
	MethodBodyOperation = 88,
	ConstructorBodyOperation = 89,
	Discard = 90,
	FlowCapture = 91,
	FlowCaptureReference = 92,
	IsNull = 93,
	CaughtException = 94,
	StaticLocalInitializationSemaphore = 95,
	FlowAnonymousFunction = 96
}

g_LuaStr2CsStrCaches = {}
g_CsStr2LuaStrCaches = {}

function forwardtocsstr(str)
    if str==nil then
        return nil        
    elseif type(str)=="string" then
        return System.String.ctor__A_Char(str)
    else
        return str
    end
end

function csstrtoluastr(str)
    if str==nil then
        return nil
    elseif type(str)=="userdata" then
        local meta = getmetatable(str)
        if meta and rawget(meta, "__typename")=="String" then
            local v = g_CsStr2LuaStrCaches[str]
            if v==nil then
                local s = tostring(str)
                g_CsStr2LuaStrCaches[str] = s
                return s
            else
                return v
            end
        else
            return str
        end
    else
        return str
    end
end

function luastrtocsstr(str)
    if str==nil then
        return nil
    elseif type(str)=="string" then
        local v = g_LuaStr2CsStrCaches[str]
        if v==nil then
            local s = forwardtocsstr(str)
            g_LuaStr2CsStrCaches[str] = s
            return s
        else
            return v
        end
    else
        return str
    end
end

function stringconcat(str1, str2)
    return System.String.Concat__String__String(str1, str2)
end

function paramtypecheck(obj, class)
    return obj
end

function getStack()
    return debug.traceback()
end

function printStack()
    Utility.Warn("{0}", debug.traceback())
end

function printJitStatus()
    local infos = System.Text.StringBuilder.ctor()
    local results = {jit.status()}
    Utility.AppendFormat(infos, "jit status count {0}", #results)
    infos:AppendLine()
    for i, v in ipairs(results) do
        if i == 1 then
            Utility.AppendFormat(infos, "jit status {0}", v)
        else
            Utility.AppendFormat(infos, " {0}", v)
        end
        infos:AppendLine()
    end
    UnityEngine.Debug.Log__Object(infos:ToString())
end

jit.off()
jit.flush()
printJitStatus()

if not package.loading then
    package.loading = {}
end

local rawrequire = require
-- a chatty version of the actual import function above
function require(x)
    local ret = nil
    if package.loading[x] == nil then
        package.loading[x] = true
        --print('loading started for ' .. x)
        ret = rawrequire(x)
        --print('loading ended for ' .. x)
        package.loading[x] = nil
    else
        ret = package.loaded[x]
        --print('already loading ' .. x)
    end
    return ret
end

local function wrap_max(...)
    return math.max(...)
end

local function wrap_min(...)
    return math.min(...)
end

LuaConsole = {
    Write = function(...)
        io.write(...)
    end,
    Print = function(...)
        print(...)
    end
}

Cs2LuaLibrary = {
    IsCs2Lua = function(obj)
        if obj then
            local meta = getmetatable(obj)
            if meta and rawget(meta, "__cs2lua_defined") then
                return true
            end
        end
        return false
    end,
    FormatString = function(fmt, ...)
        return Utility.LuaFormat(fmt, ...);
    end,
    ToString = function(T, val)
        return tostring(val)
    end,
    GetType = function(T, val)
        if type(val) == "number" then
            return System.Int32
        elseif type(val) == "string" then
            return System.String
        else
            return val:GetType()
        end
    end,
    Max = wrap_max,
    Min = wrap_min,
    Max__Single__Single = wrap_max,
    Max__Int32__Int32 = wrap_max,
    Max__UInt32__UInt32 = wrap_max,
    Min__Single__Single = wrap_min,
    Min__Int32__Int32 = wrap_min,
    Min__UInt32__UInt32 = wrap_min,
}

function settempmetatable(class)
    setmetatable(
        class,
        {
            __index = function(tb, key)
                setmetatable(class, nil)
                class.__define_class()
                return tb[key]
            end,
            __newindex = function(tb, key, val)
                setmetatable(class, nil)
                class.__define_class()
                tb[key] = val
            end,
            __call = function(...)
                setmetatable(class, nil)
                class.__define_class()
                return class(...)
            end
        }
    )
    rawset(class, "__cs2lua_predefined", true)
end

function lualog(fmt, ...)
    Utility.Warn(fmt, ...);
end

function translationlog(fmt, ...)
    Utility.Warn(fmt, ...);
end

function luausing(func, ...)
    if nil==func then
        return true, 0
    else
        return pcall(func, ...)
    end
end

function luapcall_geterror(e)
    local err = tostring(e)
    local trace = debug.traceback(err)
    UnityEngine.Debug.LogError__Object(err .. ", " .. trace)
    return err
end

function luapcall(func, ...)
    if nil==func then
        return false, "nil luapcall function"
    else
        return xpcall(
            func,
            luapcall_geterror,
            ...
        )
    end
end

function luatry_geterror(e)
    local err = tostring(e)
    local trace = debug.traceback(err)
    UnityEngine.Debug.LogError__Object(err .. ", " .. trace)
    return {err, trace}
end

function luatry(func, ...)
    if nil==func then
        return true, 0
    else
        return xpcall(
            func,
            luatry_geterror,
            ...
        )
    end
end

function luacatch(handled, err, func)
    local retval = nil
    if not handled and func then
        retval = func({Message = err[1], StackTrace = err[2], ToString = function() return Message end})
    end
    return retval
end

function luathrow(obj)
    if type(obj) == "string" then
        error(obj)
    else
        error(obj.Message)
    end
end

function luaunpack(arr)
    local meta = getmetatable(arr)
    if meta and rawget(meta, "__cs2lua_defined") then
        return unpack(arr)
    else
        if type(arr) == "userdata" then
            local tb = {}
            for i=1,#arr do
                tb[i] = arr[i]
            end
            return tb;
        end
        return arr
    end
end

function callexternextension(callerClass, method, ...)
    local obj = ...
    if calllerClass == System.Linq.Enumerable then
        error("can't call linq extension method !")
    else
        return obj[method](...);
    end
end

function getexternstaticindexer(elementType, elementTypeKind, callerClass, class, name, argCount, ...)
    return class[name](...)
end
function getexterninstanceindexer(elementType, elementTypeKind, callerClass, obj, class, name, argCount, ...)
    local arg1,arg2 = ...
    local index
    local meta = getmetatable(obj)
    if meta then
        local _class = rawget(meta, "__class")
        if _class == System.Collections.Generic.List_T then
            index = __unwrap_if_string(arg1)
            return obj[index + 1]
        elseif _class == System.Collections.Generic.Dictionary_TKey_TValue then
            index = __unwrap_if_string(arg1)
            return obj[index]
        else
            index = __unwrap_if_string(arg1)
            if nil == index then
                UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
                return nil
            end
            local typename = rawget(meta, "__typename")
            if typename == "LuaArray" then
                return obj[index + 1]
            elseif typename == "LuaVarObject" then
                return obj[index]
            elseif name == "get_Chars" then
                local c = LuaSystemString.GetChar(obj, index)
                if not c then
                    error("index out of range")
                end
                return c
            else
                return obj:getItem(index)
            end
        end
    end
end

function setexternstaticindexer(elementType, elementTypeKind, callerClass, class, name, argCount, ...)
    return class[name](...)
end
function setexterninstanceindexer(elementType, elementTypeKind, callerClass, obj, class, name, argCount, ...)
    local arg1,arg2,arg3 = ...
    local index,val
    index = __unwrap_if_string(arg1)
    val = arg2
    if nil == index then
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
        return
    end
    local meta = getmetatable(obj)
    if meta then
        local _class = rawget(meta, "__class")
        local typename = rawget(meta, "__typename")
        if _class == System.Collections.Generic.List_T then
            obj[index + 1] = val
        elseif _class == System.Collections.Generic.Dictionary_TKey_TValue then
            obj[index] = val
        elseif typename == "LuaArray" then
            obj[index + 1] = val
        elseif typename == "LuaVarObject" then
            obj[index] = val
        else
            obj:setItem(index, val)
        end
    end
    return nil
end

function addtofuncinfostructlist(funcInfo, class, obj)
    if not funcInfo or not class or not obj then return end 
    if class==UnityEngine.Vector2 then
        table.insert(funcInfo.v2_list, obj)
    elseif class==UnityEngine.Vector3 then
        table.insert(funcInfo.v3_list, obj)
    elseif class==UnityEngine.Vector4 then
        table.insert(funcInfo.v4_list, obj)
    elseif class==UnityEngine.Quaternion then
        table.insert(funcInfo.q_list, obj)
    elseif class==UnityEngine.Color then
        table.insert(funcInfo.c_list, obj)
    elseif class==UnityEngine.Color32 then
        table.insert(funcInfo.c32_list, obj)
    elseif class==UnityEngine.Rect then
        table.insert(funcInfo.rt_list, obj)
    elseif class==CsLibrary.DateTime then
        table.insert(funcInfo.dt_list, obj)
    elseif class==CsLibrary.TimeSpan then
        table.insert(funcInfo.ts_list, obj)
    end
end

function invokeexternoperatorreturnstructimpl(funcInfo, rettype, class, method, ...)
    local arg1,arg2 = ...
    local marg1 = arg1 and getmetatable(arg1)
    local marg2 = arg2 and getmetatable(arg2)
    --对slua，对应到lua元表操作符函数的操作符重载cs2lua转lua代码时已经换成对应操作符表达式。
    --执行到这里的应该是无法对应到lua操作符的操作符重载
    if rettype==System.Boolean and class==System.Type then
        if method=="op_Equality" then
            return arg1==arg2
        elseif method=="op_Inequality" then
            return arg1~=arg2
        end
    end
    if arg1==nil and method == "op_Equality" then
        return Slua.IsNull(arg2)
    elseif arg1==nil and 1 == string.find(method, "op_Equality__", 1, true) then
        return Slua.IsNull(arg2)
    elseif arg1==nil and method == "op_Inequality" then
        return not Slua.IsNull(arg2)
    elseif arg1==nil and 1 == string.find(method, "op_Inequality__", 1, true) then
        return not Slua.IsNull(arg2)
    elseif arg1~=nil and arg2==nil and method == "op_Equality" then
        return Slua.IsNull(arg1)
    elseif arg1~=nil and arg2==nil and method == "op_Inequality" then
        return not Slua.IsNull(arg1)
    elseif arg1~=nil and arg2~=nil and method == "op_Equality" then
        return class[method](...)
    elseif arg1~=nil and arg2~=nil and method == "op_Inequality" then
        return class[method](...)
    elseif method == "op_Implicit" or 1 == string.find(method, "op_Implicit__", 1, true) then
        local t = nil
        if marg1 then
            t = rawget(marg1, "__typename")
        end
        if class == UnityEngine.Vector4 then
            if t == "Vector3" then
                local v4 = UnityEngine.Vector4.New(arg1.x,arg1.y,arg1.z)
                table.insert(funcInfo.v4_list, v4)
                return v4
            elseif t == "Vector4" then
                if rettype == UnityEngine.Vector3 then
                    local v3 = UnityEngine.Vector3.New(arg1.x,arg1.y,arg1.z)
                    table.insert(funcInfo.v3_list, v3)
                    return v3
                else
                    local v2 = UnityEngine.Vector2.New(arg1.x,arg1.y)
                    table.insert(funcInfo.v2_list, v2)
                    return v2
                end
            end
        elseif class == UnityEngine.Vector2 then
            if t == "Vector3" then
                local v2 = UnityEngine.Vector2.New(arg1.x,arg1.y)
                table.insert(funcInfo.v2_list, v2)
                return v2
            else
                local v3 = UnityEngine.Vector3.New(arg1.x,arg1.y,0)
                table.insert(funcInfo.v3_list, v3)
                return v3
            end
        elseif class == UnityEngine.Color32 then
            if t == "Color32" then
                local c = UnityEngine.Color.New(arg1.r/255.0,arg1.g/255.0,arg1.b/255.0,arg1.a/255.0)
                table.insert(funcInfo.c_list, c)
                return c
            else
                local c32 = Color32Pool.Alloc()
                table.insert(funcInfo.c32_list, c32)
                c32.x = arg1.r * 255
                c32.y = arg1.g * 255
                c32.z = arg1.b * 255
                c32.w = arg1.a * 255
                return c32
            end
        elseif class == BoxedValue then
            return class[method](arg1)
        else
            --这里就不仔细判断了，就假定是UnityEngine.Object子类了
            return not Slua.IsNull(arg1)
        end
    elseif method == "op_Multiply" or 1 == string.find(method, "op_Multiply__", 1, true) then
        if arg1~=nil and arg2~=nil then
            local t1 = nil
            local t2 = nil
            if marg1 then
                t1 = rawget(marg1, "__typename")
            end
            if marg2 then
                t2 = rawget(marg2, "__typename")
            end
            if t1=="Vector2" and type(arg2)=="number" then
                local v2 = UnityEngine.Vector2.New(arg1.x*arg2,arg1.y*arg2)
                table.insert(funcInfo.v2_list, v2)
                return v2
            elseif type(arg1)=="number" and t2=="Vector2" then
                local v2 = UnityEngine.Vector2.New(arg2.x*arg1,arg2.y*arg1)
                table.insert(funcInfo.v2_list, v2)
                return v2
            elseif t1=="Vector2" and type(arg2)=="Vector2" then
                local v2 = UnityEngine.Vector2.New(arg1.x*arg2.x,arg1.y*arg2.y)
                table.insert(funcInfo.v2_list, v2)
                return v2
            elseif t1=="Vector3" and type(arg2)=="number" then
                local v3 = UnityEngine.Vector3.New(arg1.x*arg2,arg1.y*arg2,arg1.z*arg2)
                table.insert(funcInfo.v3_list, v3)
                return v3
            elseif type(arg1)=="number" and t2=="Vector3" then
                local v3 = UnityEngine.Vector3.New(arg2.x*arg1,arg2.y*arg1,arg2.z*arg1)
                table.insert(funcInfo.v3_list, v3)
                return v3
            elseif t1=="Vector4" and type(arg2)=="number" then
                local v4 = UnityEngine.Vector4.New(arg1.x*arg2,arg1.y*arg2,arg1.z*arg2,arg1.w*arg2)
                table.insert(funcInfo.v4_list, v4)
                return v4
            elseif type(arg1)=="number" and t2=="Vector4" then
                local v4 = UnityEngine.Vector4.New(arg2.x*arg1,arg2.y*arg1,arg2.z*arg1,arg2.w*arg1)
                table.insert(funcInfo.v4_list, v4)
                return v4
            elseif t1=="Color" and type(arg2)=="number" then
                local c = UnityEngine.Color.New(arg1.r*arg2,arg1.g*arg2,arg1.b*arg2,arg1.a*arg2)
                table.insert(funcInfo.c_list, c)
                return c
            elseif type(arg1)=="number" and t2=="Color" then
                local c = UnityEngine.Color.New(arg2.r*arg1,arg2.g*arg1,arg2.b*arg1,arg2.a*arg1)
                table.insert(funcInfo.c_list, c)
                return c
            elseif t1 =="Vector2" and t2 == "Vector2" then
                local v2= UnityEngine.Vector2.New(arg1.x*arg2.x,arg1.y*arg2.y)
                table.insert(funcInfo.v2_list,v2)
                return v2
            else
                local re = class[method](...)
                addtofuncinfostructlist(funcInfo, rettype, re);
                return re
            end
        elseif arg1~=nil and arg2~=nil then
            if type(arg1)=="number" and type(arg2)=="number" then
                return arg1 * arg2
            else
                local re = class[method](...)
                addtofuncinfostructlist(funcInfo, rettype, re);
                return re
            end
        end
    elseif method == "op_Division" or 1 == string.find(method, "op_Division__", 1, true) then
        if arg1~=nil and arg2~=nil then
            local t1 = nil
            local t2 = nil
            if marg1 then
                t1 = rawget(marg1, "__typename")
            end
            if marg2 then
                t2 = rawget(marg2, "__typename")
            end
            if t1=="Vector2" and type(arg2)=="number" then
                local v2 = Vector2Pool.Alloc()
                table.insert(funcInfo.v2_list, v2)
                v2.x = arg1.x/arg2
                v2.y = arg1.y/arg2
                return v2
            elseif t1=="Vector3" and type(arg2)=="number" then
                local v3 = Vector3Pool.Alloc()
                table.insert(funcInfo.v3_list, v3)
                v3.x = arg1.x/arg2
                v3.y = arg1.y/arg2
                v3.z = arg1.z/arg2
                return v3
            elseif t1=="Vector4" and type(arg2)=="number" then
                local v4 = Vector4Pool.Alloc()
                table.insert(funcInfo.v4_list, v4)
                v4.x = arg1.x/arg2
                v4.y = arg1.y/arg2
                v4.z = arg1.z/arg2
                v4.w = arg1.w/arg2
                return v4
            elseif t1=="Color" and type(arg2)=="number" then
                local c = ColorPool.Alloc()
                table.insert(funcInfo.c_list, c)
                c.x = arg1.r/arg2
                c.y = arg1.g/arg2
                c.z = arg1.b/arg2
                c.w = arg1.a/arg2
                return c
            else
                local re = class[method](...)
                addtofuncinfostructlist(funcInfo, rettype, re);
                return re
            end
        elseif arg1~=nil and arg2~=nil then
            if type(arg1)=="number" and type(arg2)=="number" then
                return arg1 / arg2
            else
                local re = class[method](...)
                addtofuncinfostructlist(funcInfo, rettype, re);
                return re
            end
        end
    elseif method == "op_Addition" or method == "op_Subtraction" or 1 == string.find(method, "op_Addition__", 1, true) or 1 == string.find(method, "op_Subtraction__", 1, true) then
        local re = class[method](...)
        addtofuncinfostructlist(funcInfo, rettype, re);
        return re
    end
    if method then        
        local re = class[method](...)
        addtofuncinfostructlist(funcInfo, rettype, re);
        return re
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end

function invokeexternoperatorreturnstruct(rettype, class, method, ...)
    return class[method](...)
end

function invokeoperator(rettype, class, method, ...)
    return class[method](...)
end

function invokeexternoperator(rettype, class, method, ...)
    local arg1,arg2 = ...
    if rettype==System.Boolean and class==System.Type then
        if method=="op_Equality" then
            return arg1==arg2
        elseif method=="op_Inequality" then
            return arg1~=arg2
        end
    end
    if arg1==nil and (method == "op_Equality" or 1 == string.find(method, "op_Equality__", 1, true)) then
        return Slua.IsNull(arg2)
    elseif arg1==nil and (method == "op_Inequality" or 1 == string.find(method, "op_Inequality__", 1, true)) then
        return not Slua.IsNull(arg2)
    elseif arg1~=nil and arg2==nil and (method == "op_Equality" or 1 == string.find(method, "op_Equality__", 1, true)) then
        return Slua.IsNull(arg1)
    elseif arg1~=nil and arg2==nil and (method == "op_Inequality" or 1 == string.find(method, "op_Inequality__", 1, true)) then
        return not Slua.IsNull(arg1)
    elseif method == "op_Implicit" or 1 == string.find(method, "op_Implicit__", 1, true) then
        if class == BoxedValue then
            return class[method](arg1,arg2)
        else
            --这里就不仔细判断了，就假定是UnityEngine.Object子类了
            return not Slua.IsNull(arg1)
        end
    elseif method == "op_Multiply" or 1 == string.find(method, "op_Multiply__", 1, true) then
        if arg1~=nil and arg2~=nil then
            return class[method](...)
        elseif arg1~=nil and arg2~=nil then
            if type(arg1)=="number" and type(arg2)=="number" then
                return arg1 * arg2
            else
                return class[method](...)
            end
        end
    elseif method == "op_Division" or 1 == string.find(method, "op_Division__", 1, true) then
        if arg1~=nil and arg2~=nil then
            return class[method](...)
        elseif arg1~=nil and arg2~=nil then
            if type(arg1)=="number" and type(arg2)=="number" then
                return arg1 / arg2
            else
                return class[method](...)
            end
        end
    end
    if method then        
        return class[method](...)
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end

local function _get_first_untable_from_pack_args(...)
    local arg1, arg2 = ...
    if arg1 or arg2 then
        if type(arg1) == "table" then
            return arg1[1], arg1[2]
        else
            return arg1, arg2
        end
    end
end

function callbasicvalue(obj, isEnum, class, method, ...)
    local arg1,arg2 = ...
    local meta = getmetatable(obj)
    if isEnum and obj and (method == "ToString" or 1 == string.find(method, "ToString__")) then
        return class.Value2String[obj]
    end
    if method then
        if class == System.Char and (method == "ToString" or 1 == string.find(method, "ToString__")) then
            return Utility.CharToString(obj)
        elseif class == System.String then
            local f = LuaSystemString[method]
            if f then
                return f(obj, ...) 
            else
                local csstr = obj
                if type(obj) == "string" then
                    csstr = forwardtocsstr(obj)
                end
                return csstr[method](csstr, ...)
            end
        elseif class == System.Single and method == "ToString__String" then
            return Utility.SingleToString(obj, arg1)
        elseif class == System.Double and method == "ToString__String" then
            return Utility.DoubleToString(obj, arg1)
        elseif class == System.Int32 and method == "ToString__String" then
            return Utility.IntToString(obj, arg1)
        elseif class == System.UInt32 and method == "ToString__String" then
            return Utility.UintToString(obj, arg1)
        elseif meta then
            return obj[method](obj, ...)
        elseif method == "CompareTo" or 1 == string.find(method, "CompareTo__") then            
            if type(obj)=="boolean" and type(arg1)=="boolean" then
                if obj and arg1 then
                    return 0
                elseif not obj and not arg1 then
                    return 0
                elseif obj and not arg1 then
                    return 1
                else
                    return -1
                end
            else
                if obj > arg1 then
                    return 1
                elseif obj < arg1 then
                    return -1
                else
                    return 0
                end
            end
        elseif method == "ToString" or 1 == string.find(method, "ToString__") then
            return tostring(obj)
        elseif method == "Split" or 1 == string.find(method, "Split__") then
            local result1, result2 = _get_first_untable_from_pack_args(...)
            if type(result1) == "number" then
                result1 = Utility.CharToString(result1)
            end
            return obj[method](obj, result1, result2)
        elseif method == "TrimStart" then
            local result = _get_first_untable_from_pack_args(...)
            if type(result) == "number" then
                result = Utility.CharToString(result)
            end
            return obj[method](obj, result)
        end
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end
function getbasicvalue(obj, isEnum, class, property)
    local meta = getmetatable(obj)
    if property then
        if type(obj) == "string" then
            return LuaSystemString.GetProperty(obj, property)
            -- local csstr = System.String.ctor__A_Char(obj)
            -- return csstr[property]
        elseif meta then
            return obj[property]
        else
            if type(obj) == "number" then
                if property == "Length" then
                    return string.len(tostring(obj))
                end
            end
            return obj[property]
        end
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end
function setbasicvalue(obj, isEnum, class, property, value)
    local meta = getmetatable(obj)
    if property then
        if type(obj) == "string" then
            local csstr = forwardtocsstr(obj)
            csstr[property] = value
        elseif meta then
            obj[property] = value
        else
            obj[property] = value
        end
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end

function callarraystaticmethod(firstArray, secondArray, method, ...)
    if nil ~= firstArray and nil ~= method then
        local arg1,arg2 = ...
        local meta = getmetatable(firstArray)
        if meta and rawget(meta, "__cs2lua_defined") then
            if ArrayStaticMethods[method] ~= nil then
                return ArrayStaticMethods[method](firstArray, secondArray, method, ...)
            else
                translationlog("need add handler for callarraystaticmethod Array.{0}", method)
                return nil
            end
        elseif method == "IndexOf" or 1 == string.find(method, "IndexOf__", 1, true) then
            local arr,val,start,count = ...
            if not start then
                start = 0
            end
            if not count then
                count = arr.Length
            end
            for i = start+1,start+count do
                if arr[i]==val then
                    return i-1
                end
            end
            return -1
        else
            --这种情形认为是外部导出的数组调用，直接调导出接口了（由于System.Array有generic成员，这些方法的调用估计会出错）
            return System.Array[method](...)
        end
    else
        translationlog("need add handler for callarraystaticmethod Array.{0}", method)
        return nil
    end
end

function callexterninterfacereturnstruct(obj, intf, method, ...)
    translationlog("need add handler for callexterninterfacereturnstruct {0}.{1}", getclasstypename(intf), method)
    return callinterface(obj, intf, method, ...)
end
function getexterninterfacestructmember(obj, intf, name, getmethodname)
    translationlog("need add handler for getexterninterfacestructmember {0}.{1}", getclasstypename(intf), name)
    return getinterface(obj, intf, name, getmethodname)
end

function callinterface(obj, intf, method, ...)
    return obj[method](obj, ...)
end
function getinterface(obj, intf, name, getmethodname)
    local meta = getmetatable(obj)
    if meta and rawget(meta, "__cs2lua_defined") then
        return obj[getmethodname](obj)
    else
        return obj[name]
    end
end
function setinterface(obj, intf, name, setmethodname, val)
    local meta = getmetatable(obj)
    if meta and rawget(meta, "__cs2lua_defined") then
        obj[setmethodname](obj, val)
    else
        obj[name] = val
    end
end

--暂时只对整数除法进行特殊处理，运算溢出暂不处理
--__cs2lua_div = 0;
--__cs2lua_mod = 1;
--__cs2lua_add = 2;
--__cs2lua_sub = 3;
--__cs2lua_mul = 4;
--__cs2lua_lshift = 5;
--__cs2lua_rshift = 6;
--__cs2lua_bitand = 7;
--__cs2lua_bitor = 8;
--__cs2lua_bitxor = 9;
--__cs2lua_bitnot = 10;
function invokeintegeroperator(op, luaop, opd1, opd2, type1, type2)
    if op == __cs2lua_div then
        local r
        if opd1 * opd2 > 0 then
            r = math.floor(opd1 / opd2)
        else
            r = -math.floor(-opd1 / opd2)
        end
        return r
    elseif op == __cs2lua_mod then
        return opd1 % opd2
    elseif op == __cs2lua_add then
        if type1 then
            return opd1 + opd2
        else
            return opd2
        end
    elseif op == __cs2lua_sub then
        if type1 then
            return opd1 - opd2
        else
            return -opd2
        end
    elseif op == __cs2lua_mul then
        return opd1 * opd2
    elseif op == __cs2lua_lshift then
        return lshift(opd1, opd2)
    elseif op == __cs2lua_rshift then
        return rshift(opd1, opd2)
    elseif op == __cs2lua_bitand then
        return bitand(opd1, opd2)
    elseif op == __cs2lua_bitor then
        return bitor(opd1, opd2)
    elseif op == __cs2lua_bitxor then
        return bitxor(opd1, opd2)
    elseif op == __cs2lua_bitnot then
        return bitnot(opd1 or opd2)
    end
end

function createpool(tag, newFunc)
    local pool = {}
    pool.Alloc = function()
            local data = nil
            if #(pool.m_Data)>0 then
                data = table.remove(pool.m_Data)
                --lualog("pool.Alloc reuse {0}:{1} stack:{2}", tag, __get_obj_string(data), getStack())
            else
                data = newFunc()
                --lualog("pool.Alloc new {0}:{1} stack:{2}", tag, __get_obj_string(data), getStack())
            end
            return data
        end
    pool.Recycle = function(data)
            --lualog("pool.Recycle {0}:{1} count:{2}", tag, __get_obj_string(data), #(pool.m_Data)+1)
            local exists = false
            for i,v in ipairs(pool.m_Data) do
                if rawequal(v,data) then
                    exists=true
                    lualog("pool.Recycle {0}:{1} duplicate !", tag, __get_obj_string(data))
                    printStack()
                    break
                end
            end
            if not exists then
                table.insert(pool.m_Data, data)
            end
        end
    pool.m_Data = {}
    return pool
end

g_FuncInfoStack = {}

g_FuncInfoPool = createpool("FuncInfo",
    function()
        return {
            iter_list = {},
            v2_list = {},
            v3_list = {},
            v4_list = {},
            q_list = {},
            c_list = {},
            c32_list = {},
            rt_list = {},
        }
    end)
Vector2Pool = createpool("Vector2",
    function()
        return UnityEngine.Vector2.NewFunc()
    end)
Vector3Pool = createpool("Vector3",
    function()
        return UnityEngine.Vector3.NewFunc()
    end)
Vector4Pool = createpool("Vector4",
    function()
        return UnityEngine.Vector4.NewFunc()
    end)
QuaternionPool = createpool("Quaternion",
    function()
        return UnityEngine.Quaternion.NewFunc()
    end)
ColorPool = createpool("Color",
    function()
        return UnityEngine.Color.NewFunc()
    end)
Color32Pool = createpool("Color32",
    function()
        return UnityEngine.Color32.ctor()
    end)
RectPool = createpool("Rect",
    function()
        return UnityEngine.Rect.ctor()
    end)

--slua机制（不支持c# StopCoroutine）
function wrapenumerable0(func)
    return function(...)
        local args = {...}
        return UnityEngine.WrapEnumerator(
            coroutine.create(
                function()
                    func(unpack(args))
                end
            )
        )
    end
end

function wrapyield0(yieldVal, isEnumerableOrEnumerator, isUnityYield)
    UnityEngine.Yield(yieldVal)
end

--xlua协程机制（支持c# StopCoroutine）
function wrapenumerable(func)
    return function(...)
        local args = {...}
        return UnityEngine.WrapEnumerator2(
            coroutine.wrap(
                function()
                    func(unpack(args))
                    return Slua.yieldbreak
                end
            )
        )
    end
end

function wrapyield(yieldVal, isEnumerableOrEnumerator, isUnityYield)
    coroutine.yield(yieldVal)
end

function wrapconst(t, name)
    if name then
        return t[name]
    else
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
    end
    return nil
end

function wrapchar(char, intVal)
    if intVal > 0 then
        return intVal
    else
        local str = tostring(char)
        local l = string.len(str)
        if l == 1 then
            local first = string.byte(str, 1, 1)
            return first
        elseif l == 2 then
            local first = string.byte(str, 1, 1)
            local second = string.byte(str, 2, 2)
            return first + second * 0x100
        else
            return 0
        end
    end
end

function wrapoutstruct(v, classObj)
    return v
end

function wrapoutexternstruct(v, classObj)
    translationlog("need add handler for wrapoutexternstruct {0}", getclasstypename(classObj))
    return v
end

function wrapstruct(v, classObj)
    return v
end

function wrapexternstruct(v, classObj)
    translationlog("need add handler for wrapexternstruct {0}", getclasstypename(classObj))
    return v
end

function wrapstructargument(v, argType, argOperKind, argSymKind)
    return v
end

function wrapexternstructargument(v, argType, argOperKind, argSymKind)
    translationlog("need add handler for wrapexternstructargument {0}", getclasstypename(argType))
    return v
end

function wrapstructarguments(arr, argType, argOperKind, argSymKind)
    return arr
end

function wrapexternstructarguments(arr, argType, argOperKind, argSymKind)
    translationlog("need add handler for wrapexternstructarguments {0}", getclasstypename(argType))
    return arr
end

function getexternstaticstructmember(symKind, class, member)
    translationlog("need add handler for getexternstaticstructmember {0}.{1}", getclasstypename(class), member)
    return class[member]
end

function getexterninstancestructmember(symKind, obj, class, member)
    if class==System.Nullable_T then
        if member=="Value" then
            return obj
        elseif member=="HasValue" then
            return nil~=obj
        end
    end
    translationlog("need add handler for getexterninstancestructmember {0}.{1}", getclasstypename(class), member)
    return obj[member]
end

function callexterndelegationreturnstruct(funcobj, funcobjname, ...)
    translationlog("need add handler for callexterndelegationreturnstruct {0}", funcobjname)
    return funcobj(...)
end

function callexternextensionreturnstruct(class, member, ...)
    translationlog("need add handler for callexternextensionreturnstruct {0}.{1}", getclasstypename(class), member)
    return class[member](...)
end

function callexternstaticreturnstruct(class, member, ...)
    translationlog("need add handler for callexternstaticreturnstruct {0}.{1}", getclasstypename(class), member)
    return class[member](...)
end

function callexterninstancereturnstruct(obj, class, member, ...)
    translationlog("need add handler for callexterninstancereturnstruct {0}.{1}", getclasstypename(class), member)
    return obj[member](obj, ...)
end

function getstaticindexerstructimpl(isExtern, elementType, callerClass, class, name, argCount, ...)
    return class[name](...)
end
function getinstanceindexerstructimpl(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
    local arg1,arg2 = ...
    local index
    local meta = getmetatable(obj)
    if meta then
        local _class = rawget(meta, "__class")
        if _class == System.Collections.Generic.List_T then
            index = __unwrap_if_string(arg1)
            return obj[index + 1]
        elseif _class == System.Collections.Generic.Dictionary_TKey_TValue then
            index = __unwrap_if_string(arg1)
            return obj[index]
        else
            index = __unwrap_if_string(arg1)
            if nil == index then
                UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
                return nil
            end
            local typename = rawget(meta, "__typename")
            if typename == "LuaArray" then
                return obj[index + 1]
            elseif typename == "LuaVarObject" then
                return obj[index]
            elseif name == "get_Chars" then
                local c = LuaSystemString.GetChar(obj, index)
                if not c then
                    error("index out of range")
                end
                return c
            else
                return obj:getItem(index)
            end
        end
    end
end

function getstaticindexerstruct(isExtern, elementType, callerClass, class, name, argCount, ...)
    if isExtern and callerClass ~= class then
        translationlog("need add handler for getstaticindexerstruct {0}[{1}] {2}.{3}", getclasstypename(callerClass), getclasstypename(elementType), getclasstypename(class), name)
    end
    return getstaticindexerstructimpl(isExtern, elementType, callerClass, class, name, argCount, ...)
end
function getinstanceindexerstruct(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
    if isExtern and callerClass ~= class then
        translationlog("need add handler for getinstanceindexerstruct {0}[{1}] {2}.{3}", getclasstypename(callerClass), getclasstypename(elementType), getclasstypename(class), name)
    end
    return getinstanceindexerstructimpl(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
end

function setstaticindexerstructimpl(isExtern, elementType, callerClass, class, name, argCount, ...)
    return class[name](...)
end
function setinstanceindexerstructimpl(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
    local arg1,arg2,arg3 = ...
    local index,val
    index = __unwrap_if_string(arg1)
    val = arg2
    if nil == index then
        UnityEngine.Debug.LogError__Object("[cs2lua] table index is nil")
        return
    end
    local meta = getmetatable(obj)
    if meta then
        local _class = rawget(meta, "__class")
        local typename = rawget(meta, "__typename")
        if _class == System.Collections.Generic.List_T then
            obj[index + 1] = val
        elseif _class == System.Collections.Generic.Dictionary_TKey_TValue then
            obj[index] = val
        elseif typename == "LuaArray" then
            obj[index + 1] = val
        elseif typename == "LuaVarObject" then
            obj[index] = val
        else
            obj:setItem(index, val)
        end
    end
    return nil
end

function setstaticindexerstruct(isExtern, elementType, callerClass, class, name, argCount, ...)
    translationlog("need add handler for setstaticindexerstruct {0}[{1}] {2}.{3}", getclasstypename(callerClass), getclasstypename(elementType), getclasstypename(class), name)
    return setstaticindexerstructimpl(isExtern, elementType, callerClass, class, name, argCount, ...)
end
function setinstanceindexerstruct(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
    translationlog("need add handler for setinstanceindexerstruct {0}[{1}] {2}.{3}", getclasstypename(callerClass), getclasstypename(elementType), getclasstypename(class), name)
    return setinstanceindexerstructimpl(isExtern, elementType, callerClass, obj, class, name, argCount, ...)
end

function arraygetstructimpl(isExtern, arrSymKind, elementType, arr, argCount, ...)
    local num = select("#", ...)
    if num == 1 then
        local v1 = select(1, ...)
        return arr[v1]
    elseif num == 2 then
        local v1 = select(1, ...)
        local v2 = select(2, ...)
        return arr[v1][v2]
    elseif num == 3 then
        local v1 = select(1, ...)
        local v2 = select(2, ...)
        local v3 = select(3, ...)
        return arr[v1][v2][v3]
    else
        error("too many dimensions !")
    end
end
function arraysetstructimpl(isExtern, arrSymKind, elementType, arr, argCount, ...)
    local num = select("#", ...)
    if num == 2 then
        local v1 = select(1, ...)
        local val = select(2, ...)
        arr[v1] = val
    elseif num == 3 then
        local v1 = select(1, ...)
        local v2 = select(2, ...)
        local val = select(3, ...)
        arr[v1][v2] = val
    elseif num == 4 then
        local v1 = select(1, ...)
        local v2 = select(2, ...)
        local v3 = select(3, ...)
        local val = select(4, ...)
        arr[v1][v2][v3] = val
    else
        error("too many dimensions !")
    end
end

function arraygetstruct(isExtern, arrSymKind, elementType, arr, argCount, ...)   
    if isExtern then 
        translationlog("need add handler for arraygetstruct {0}[]", getclasstypename(elementType))
    end
    return arraygetstructimpl(isExtern, arrSymKind, elementType, arr, argCount, ...)
end
function arraysetstruct(isExtern, arrSymKind, elementType, arr, argCount, ...)
    translationlog("need add handler for arraysetstruct {0}[]", getclasstypename(elementType))
    arraysetstructimpl(isExtern, arrSymKind, elementType, arr, argCount, ...)
end

function recycleandkeepstructvalue(fieldType, oldVal, newVal)
    translationlog("need add handler for recycleandkeepstructvalue {0}", getclasstypename(fieldType))
end

function luatableremove(tb, val)
    for i,v in ipairs(tb) do
        if rawequal(v,val) then
            table.remove(tb, i)
            return true
        end
    end
    return false
end

function recycleandkeepcheck(fieldType, oldVal, newVal)   
    if rawequal(oldVal,newVal) then
        lualog("[recycleandkeepstructvalue] oldVal==newVal")
        printStack()
    end
end

function removefromcallerfuncinfo(funcinfo, class, val)
    translationlog("need add handler for removefromcallerfuncinfo {0}", getclasstypename(class))
end

function removefromfuncinfo(funcinfo, class, val)
    translationlog("need add handler for removefromfuncinfo {0}", getclasstypename(class))
end

function movetocallerfuncinfo(funcInfo, class, val)
    translationlog("need add handler for movetocaller {0}", getclasstypename(class))
end

function luagetcallerfuncinfo()
    local ct = #g_FuncInfoStack
    if ct > 1 then
        return g_FuncInfoStack[ct-1]
    else
        return nil
    end
end

function luainitialize()
    local info = g_FuncInfoPool.Alloc()
    table.insert(g_FuncInfoStack, info)
    return info
end

function luafinalize(funcInfo)
    local last = table.remove(g_FuncInfoStack)
    while last and last ~= funcInfo do
        last = table.remove(g_FuncInfoStack)
    end
    if funcInfo then
        for i,v in ipairs(funcInfo.iter_list) do
            recycleiterator(nil, v)
        end
        for i,v in ipairs(funcInfo.v2_list) do
            Vector2Pool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.v3_list) do
            Vector3Pool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.v4_list) do
            Vector4Pool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.q_list) do
            QuaternionPool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.c_list) do
            ColorPool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.c32_list) do
            Color32Pool.Recycle(v)
        end
        for i,v in ipairs(funcInfo.rt_list) do
            RectPool.Recycle(v)
        end
        local ct
        ct = #(funcInfo.iter_list)
        for i=1,ct do
            funcInfo.iter_list[i]=nil
        end
        ct = #(funcInfo.v2_list)
        for i=1,ct do
            funcInfo.v2_list[i]=nil
        end
        ct = #(funcInfo.v3_list)
        for i=1,ct do
            funcInfo.v3_list[i]=nil
        end
        ct = #(funcInfo.v4_list)
        for i=1,ct do
            funcInfo.v4_list[i]=nil
        end
        ct = #(funcInfo.q_list)
        for i=1,ct do
            funcInfo.q_list[i]=nil
        end
        ct = #(funcInfo.c_list)
        for i=1,ct do
            funcInfo.c_list[i]=nil
        end
        ct = #(funcInfo.c32_list)
        for i=1,ct do
            funcInfo.c32_list[i]=nil
        end
        ct = #(funcInfo.rt_list)
        for i=1,ct do
            funcInfo.rt_list[i]=nil
        end
        g_FuncInfoPool.Recycle(funcInfo)
    end
    return nil
end

Cs2LuaCustomData = {
	__new_object = function(...)
		local __cs2lua_newobj = newobject(Cs2LuaCustomData, nil, nil, nil, 0, nil, ...);
		return __cs2lua_newobj;
	end,
	__define_class = function()
		printMemDiff("Cs2LuaCustomData::__define_class begin");

		local class = Cs2LuaCustomData;
		local obj_methods = nil;

		local __defineclass_return = defineclass(UnityEngine.Object, "Cs2LuaCustomData", "Cs2LuaCustomData", class, obj_methods, false, true);
		printMemDiff("Cs2LuaCustomData::__define_class end");
		return __defineclass_return;
	end,
	__obj_fields = {
	    CustomData = true,
	},
};

settempmetatable(Cs2LuaCustomData);

function luatoobject(symKind, isStatic, symName, arg1, ...)
    if arg1 and symKind==SymbolKind.Field then
        local meta = getmetatable(arg1)
        if meta and rawget(meta, "__cs2lua_defined") then
            --lualog("luatoobject symKind:{0} {1} {2} {3}", symKind, isStatic, symName, meta.__cs2lua_fullname)
            --printStack()
            local o = Cs2LuaCustomData.__new_object()
            o.CustomData = arg1
            arg1 = o
        end
    end
    return arg1, ...
end

function objecttolua(arg1, ...)
    if arg1 then
        local meta = getmetatable(arg1)       
        if meta and rawget(meta, "__cs2lua_fullname")=="Cs2LuaCustomData" then   
            arg1 = arg1.CustomData
            --local metav = getmetatable(arg1)
            --lualog("objecttolua:{0} {1}", meta.__cs2lua_fullname, metav.__cs2lua_fullname)
            --printStack()
        end
    end
    return arg1, ...
end

__mt_delegation = {
    __is_delegation = true,
    __call = function(t, ...)
        local ret = nil
        for k, v in pairs(t) do
            if v then
                ret = v(...)
            end
        end
        return ret
    end
}

function wrapdelegation(handlers)
    return setmetatable(handlers, __mt_delegation)
end

function __get_obj_string(obj)
    if type(obj) == "table" then
        local oldTblMeta = getmetatable(obj)
        setmetatable(obj, nil)
        local s = tostring(obj)
        setmetatable(obj, oldTblMeta)
        return s
    else
        return tostring(obj)
    end
end

__cs2lua_delegations = setmetatable({},{ __mode = 'v' })

function calcdelegationkey(class_member_key, obj)
    local fk = class_member_key .. __get_obj_string(obj)
    return fk
end
function getdelegation(key)
    return rawget(__cs2lua_delegations, key)
end
function builddelegationonce(key, handler)
    local old = rawget(__cs2lua_delegations, key)
    if old~=handler then
        rawset(__cs2lua_delegations, key, handler)
    end
    return handler
end

function dumpdelegationtable()
    print("dumpdelegationtable")

    if next(__cs2lua_delegations) == nil then
        print("dumpdelegationtable empty")
        return
    end

    for k, v in pairs(__cs2lua_delegations) do
        print(k)
        print(v)
    end
end

function delegationwrap(handler)
    if handler then
        local meta = getmetatable(handler)
        if meta and rawget(meta, "__is_delegation") then
            return handler
        else
            return wrapdelegation {handler}
        end
    else
        return wrapdelegation {}
    end
end

function delegationcomparewithnil(isstatic, t, k, symKind, beequal)
    if not t then
        if beequal then
            return true
        else
            return false
        end
    end
    if type(t) == "function" then
        if beequal then
            return false
        else
            return true
        end
    end
    local v = t
    if k then
        if symKind == SymbolKind.Property then
            v = t[k](t)
        else
            v = t[k]
        end
    end
    if type(v) == "function" then
        if beequal then
            return false
        else
            return true
        end
    end
    local n = (v and #v) or 0
    if beequal and n == 0 then
        return true
    elseif not isqual and n > 0 then
        return true
    else
        return false
    end
end
function delegationset(isstatic, t, k, symKind, handler)
    local v = t
    if k then
        if symKind == SymbolKind.Property then
            v = t[k](t)
        else
            v = t[k]
        end
    end
    if not v or type(v) ~= "table" then
        --取不到值或者值不是表，则有可能是普通的特性访问
        --t[k] = handler;
        return handler
    else
        local n = #v
        for i = 1, n do
            table.remove(v)
        end
        table.insert(v, handler)
        return v
    end
end
function delegationadd(isstatic, t, k, symKind, handler)
    local v = t
    if k then
        if symKind == SymbolKind.Property then
            v = t[k](t)
        else
            v = t[k]
        end
    end
    if v == nil then
        v = delegationwrap(handler)
    else
        table.insert(v, handler)
    end
    return v
end
function delegationremove(isstatic, t, k, symKind, handler)
    local v = t
    if k then
        if symKind == SymbolKind.Property then
            v = t[k](t)
        else
            v = t[k]
        end
    end
    local find = false
    local pos = 1
    for k, h in pairs(v) do
        if h == handler then
            find = true
            break
        end
        pos = pos + 1
    end
    if find then
        table.remove(v, pos)
    end
    return v
end

function externdelegationcomparewithnil(isstatic, t, k, symKind, beequal)
    local v = t
    if k then
        return true
    end
    if beequal and not v then
        return true
    elseif not beequal and v then
        return true
    else
        return false
    end
end
function externdelegationset(isstatic, t, k, symKind, handler)
    if k then
        return handler
    else
        return handler
    end
end
function externdelegationadd(isstatic, t, k, symKind, handler)
    if k then
        return {"+=", handler}
    else
        return {"+=", handler}
    end
end
function externdelegationremove(isstatic, t, k, symKind, handler)
    local ret = nil
    if k then
        ret = {"-=", handler}
    else
        ret = {"-=", handler}
    end
    return ret
end

function __calc_table_count(tb)
    local count = 0
    for k, v in pairs(tb) do
        count = count + 1
    end
    return count
end

function __get_table_data(tb)
    local meta = getmetatable(tb)
    if meta and meta.__cs2lua_data then
        return meta.__cs2lua_data
    end
    error("can't find metatable or __cs2lua_data !")
end

function __set_table_count(tb, count)
    local meta = getmetatable(tb)
    if meta then
        meta.__count = count
    end
end

function __get_table_count(tb)
    local count = 0
    local meta = getmetatable(tb)
    if meta then
        if meta.__count then
            count = meta.__count
        else
            count = __calc_table_count(meta.__cs2lua_data)
            meta.__count = count
        end
    end
    return count
end

function __inc_table_count(tb)
    local meta = getmetatable(tb)
    if meta then
        if nil ~= meta.__count then
            meta.__count = meta.__count + 1
        else
            meta.__count = __calc_table_count(meta.__cs2lua_data)
        end
    end
end

function __dec_table_count(tb)
    local meta = getmetatable(tb)
    if meta then
        if meta.__count and meta.__count > 0 then
            meta.__count = meta.__count - 1
        else
            meta.__count = __calc_table_count(meta.__cs2lua_data)
        end
    end
end

function __clear_table(tb)
    local meta = getmetatable(tb)
    if meta then
        meta.__count = 0
        meta.__cs2lua_data = {}
    end
end

function __set_array_count(tb, count)
    local meta = getmetatable(tb)
    if meta then
        meta.__count = count
    end
end

function __get_array_count(tb)
    local count = 0
    local meta = getmetatable(tb)
    if meta then
        if meta.__count then
            count = meta.__count
        else
            count = #tb
            meta.__count = count
        end
    end
    return count
end

function __inc_array_count(tb)
    local meta = getmetatable(tb)
    if meta then
        if nil ~= meta.__count then
            meta.__count = meta.__count + 1
        else
            meta.__count = #tb
        end
    end
end

function __dec_array_count(tb)
    local meta = getmetatable(tb)
    if meta then
        if meta.__count and meta.__count > 0 then
            meta.__count = meta.__count - 1
        else
            meta.__count = #tb
        end
    end
end

__mt_index_of_array_table = {
    get_Length = function(obj) 
    		    return __get_table_count(obj) 
    		end,
    get_Count = function(obj) 
    		    return __get_table_count(obj) 
    		end,
    GetLength = function(obj, ix)
            local ret = 0
            local tb = obj
            for i = 0, ix do
                ret = __get_array_count(tb)
                tb = rawget(tb, 0)
            end
            return ret
        end,
    Add = function(obj, v)
            v = __unwrap_if_string(v)
            table.insert(obj, v)
            __inc_array_count(obj)
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj);
        end,
    Remove = function(obj, p)
            local pos = 0
            local ret = nil
            local ct = __get_array_count(obj)
            for i = 1, ct do
                local v = rawget(obj, i)
                p = __unwrap_if_string(p)
                if isequal(v, p) then
                    pos = i
                    ret = v
                    break
                end
            end
            if ret then
                if pos == ct then
                    rawset(obj , pos , nil);
                else 
                    for j = pos + 1, ct , 1 do
                        local vj = rawget(obj , j)
                        rawset(obj , j-1 , vj);
                    end
                    rawset(obj , ct , nil);
                end
                -- table.remove(obj, pos)
                __dec_array_count(obj)
            end
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
            return ret
        end,
    RemoveAt = function(obj, ix)
            local ct = __get_array_count(obj)
            if ix + 1 == ct then
               rawset(obj , ct ,nil) 
            else
                for j = ix + 2, ct , 1 do
                    local vj = rawget(obj , j)
                    rawset(obj , j-1 , vj);
                end
                if ix + 1 <= ct then
                    rawset(obj , ct , nil);
                end
            end
            
            if ix + 1 <= ct then
                __dec_array_count(obj)
            end
            -- table.remove(obj, ix + 1)
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    RemoveAll = function(obj, pred)
            local deletes = {}
            local ct = __get_array_count(obj)
            for i = 1, ct do
                if pred(rawget(obj, i)) then
                    table.insert(deletes, i)
                end
            end
            for i, v in ipairs(deletes) do
                rawset(obj , i , nil)
                --table.remove(obj, v)
                __dec_array_count(obj)
            end
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    AddRange = function(obj, coll)
            local iter = newiterator(nil, coll)
            for v in getiterator(iter) do
                v = __unwrap_if_string(v)
                table.insert(obj, v)
                __inc_array_count(obj)
            end
            recycleiterator(nil, iter)
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    Insert = function(obj, ix, p)
            p = __unwrap_if_string(p)
            table.insert(obj, ix + 1, p)
            __inc_array_count(obj)
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    InsertRange = function(obj, ix, coll)
            local ct = 0
            local enumer = coll:GetEnumerator()
            while enumer:MoveNext() do
                table.insert(obj, ix + 1 + ct, enumer.Current)
                __inc_array_count(obj)
                ct = ct + 1
            end
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    RemoveRange = function(obj, ix, ct)
            for i=1,ct do
                local curCount = __get_array_count(obj)
                if ix + 1 == curCount then
                    rawset(obj , curCount ,nil) 
                else
                    for j = ix + 2, curCount , 1 do
                        local vj = rawget(obj , j)
                        rawset(obj , j-1 , vj);
                    end
                end
                if ix + 1 <= curCount then
                    __dec_array_count(obj)
                end
            end
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    IndexOf = function(obj, p, start, count)
            local ct = __get_array_count(obj)
            if count==nil then
                count = ct
            end
            if start==nil then
                start = 0
            end
            p = __unwrap_if_string(p)
            for i = start+1, ct do
                local v = rawget(obj, i)
                if rawequal(v,p) then
                    return i - 1
                end
            end
            return -1
        end,
    LastIndexOf = function(obj, p, start, count)
            local ct = __get_array_count(obj)
            if count==nil then
                count = ct
            end
            if start==nil then
                start = 0
            end
            for k = ct, start+1 do
                local v = rawget(obj, k)
                if rawequal(v,p) then
                    return k - 1
                end
            end
            return -1
        end,
    FindIndex = function(obj, p1, p2, p3)
            local ct = __get_array_count(obj)
            local start = 0
            local count = ct
            local pred = p1
            if p1~=nil and p2~=nil and p3~=nil then
                start = p1
                count = p2
                pred = p3
            elseif p1~=nil and p2~=nil then
                start = p1
                pred = p2
            end
            for i = start+1, ct do
                local v = rawget(obj, i)
                if pred(v) then
                    return i - 1
                end
            end
            return -1
        end,
    Find = function(obj, predicate)
            local ct = __get_array_count(obj)
            for i = 1, ct do
                local v = rawget(obj, i)
                if predicate(v) then
                    return v
                end
            end
            return nil
        end,
    Contains = function(obj, p)
            local ret = false
            local ct = __get_array_count(obj)
            for i = 1, ct do
                local v = rawget(obj, i)
                p = __unwrap_if_string(p)
                if rawequal(v,p) then
                    ret = true
                    break
                end
            end
            return ret
        end,
    Peek = function(obj)
            local ct = __get_array_count(obj)
            local v = rawget(obj, ct)
            return v
        end,
    Enqueue = function(obj, v)
            table.insert(obj, 1, v)
            __inc_array_count(obj)
        end,
    Dequeue = function(obj)
            local ct = __get_array_count(obj)
            local v = rawget(obj, ct)
            rawset(obj , ct ,nil)
            -- table.remove(obj, ct)
            __dec_array_count(obj)
            return v
        end,
    Push = function(obj, v)
            table.insert(obj, v)
            __inc_array_count(obj)
        end,
    Pop = function(obj)
            local ct = __get_array_count(obj)
            local v = rawget(obj, ct)
            rawset(obj , ct ,nil)
            -- table.remove(obj, num)
            __dec_array_count(obj)
            return v
        end,
    CopyTo = function(obj, arr)
            local ct = __get_array_count(obj)
            for k = 1, ct do
                arr[k] = rawget(obj, k)
            end
        end,
    ToArray = function(obj)
            local ct = __get_array_count(obj)
            local ret = wraparray({}, ct)
            for k = 1, ct do
                ret[k] = rawget(obj, k)
            end
            return ret
        end,
    Clear = function(obj)
            local ct = __get_array_count(obj)
            for i = ct, 1, -1 do
                rawset(obj , i , nil)
                -- table.remove(obj, i)
            end
            __set_array_count(obj, 0)
            -- assert(__get_array_count(obj) == #obj,"not match length count:"..__get_array_count(obj).." #len:"..#obj)
        end,
    GetEnumerator = function(obj)
            return GetArrayEnumerator(obj)
        end,
    Sort = function(obj, predicate)
            local ct = __get_array_count(obj)
            for i = 1, ct, 1 do
                local v = rawget(obj, i)
                if(isequal(v , nil)) then
                    for j = i + 1, ct , 1 do
                        local vj = rawget(obj , j)
                        rawset(obj , j-1 , vj);
                    end
                    rawset(obj , ct , nil);
                end
            end
            table.sort(
                obj,
                function(a, b)
                    return predicate(a, b) < 0
                end
            )
        end,
    GetType = function(obj)
            local meta = getmetatable(obj)
            return meta.__class
        end,
}

rawset(__mt_index_of_array_table, "BinarySearch__T", rawget(__mt_index_of_array_table, "BinarySearch"))
rawset(__mt_index_of_array_table, "BinarySearch__T__IComparer_1_T", rawget(__mt_index_of_array_table, "BinarySearch"))
rawset(__mt_index_of_array_table, "BinarySearch__Int32__Int32__T__IComparer_1_T", rawget(__mt_index_of_array_table, "BinarySearch"))
rawset(__mt_index_of_array_table, "CopyTo__A_T", rawget(__mt_index_of_array_table, "CopyTo"))
rawset(__mt_index_of_array_table, "CopyTo__A_T__Int32", rawget(__mt_index_of_array_table, "CopyTo"))
rawset(__mt_index_of_array_table, "CopyTo__Int32__A_T__Int32__Int32", rawget(__mt_index_of_array_table, "CopyTo"))
rawset(__mt_index_of_array_table, "FindIndex__Predicate_1_T", rawget(__mt_index_of_array_table, "FindIndex"))
rawset(__mt_index_of_array_table, "FindIndex__Int32__Predicate_1_T", rawget(__mt_index_of_array_table, "FindIndex"))
rawset(__mt_index_of_array_table, "FindIndex__Int32__Int32__Predicate_1_T", rawget(__mt_index_of_array_table, "FindIndex"))
rawset(__mt_index_of_array_table, "FindLastIndex__Predicate_1_T", rawget(__mt_index_of_array_table, "FindLastIndex"))
rawset(__mt_index_of_array_table, "FindLastIndex__Int32__Predicate_1_T", rawget(__mt_index_of_array_table, "FindLastIndex"))
rawset(__mt_index_of_array_table, "FindLastIndex__Int32__Int32__Predicate_1_T", rawget(__mt_index_of_array_table, "FindLastIndex"))
rawset(__mt_index_of_array_table, "IndexOf__T", rawget(__mt_index_of_array_table, "IndexOf"))
rawset(__mt_index_of_array_table, "IndexOf__T__Int32", rawget(__mt_index_of_array_table, "IndexOf"))
rawset(__mt_index_of_array_table, "IndexOf__T__Int32__Int32", rawget(__mt_index_of_array_table, "IndexOf"))
rawset(__mt_index_of_array_table, "LastIndexOf__T", rawget(__mt_index_of_array_table, "LastIndexOf"))
rawset(__mt_index_of_array_table, "LastIndexOf__T__Int32", rawget(__mt_index_of_array_table, "LastIndexOf"))
rawset(__mt_index_of_array_table, "LastIndexOf__T__Int32__Int32", rawget(__mt_index_of_array_table, "LastIndexOf"))
rawset(__mt_index_of_array_table, "Reverse__Int32__Int32", rawget(__mt_index_of_array_table, "Reverse"))
rawset(__mt_index_of_array_table, "Sort__IComparer_1_T", rawget(__mt_index_of_array_table, "Sort"))
rawset(__mt_index_of_array_table, "Sort__Comparison_1_T", rawget(__mt_index_of_array_table, "Sort"))
rawset(__mt_index_of_array_table, "Sort__Int32__Int32__IComparer_1_T", rawget(__mt_index_of_array_table, "Sort"))

for k,v in pairs(__mt_index_of_array_table) do
    rawset(System.Collections.Generic.List_T, k, v)
end

__mt_index_of_array = function(t, k)
    if k == "Length" or k == "Count" then
        return __get_array_count(t)
    else
		return __mt_index_of_array_table[k]
    end
end

__mt_index_of_dictionary_table = {
    get_Count = function(obj)
            return __get_table_count(obj)
        end,
    Add = function(obj, p1, p2)
            up1 = __unwrap_if_string(p1)     
            local data = __get_table_data(obj)
            rawset(data, up1, {Key = p1,Value = p2})
            __inc_table_count(obj)
            return p2
        end,
    Remove = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            local v = rawget(data, up)
            local ret = nil
            if v then
                ret = v.Value
                rawset(data, up, nil)
            end
            __dec_table_count(obj)
            return ret
        end,
    ContainsKey = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            if rawget(data, up) then
                return true
            end
            return false
        end,
    ContainsValue = function(obj, p)
            local ret = false 
            local data = __get_table_data(obj)     
            for k, v in pairs(data) do
                if rawequal(v.Value,p) then
                    ret = true
                    break
                end
            end
            return ret
        end,
    TryGetValue = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            local v = rawget(data, up)
            if v then
                return true, v.Value
            else
                v = rawget(data, tostring(up))
                if v then
                    return true, v.Value
                end
            end
            local meta = getmetatable(obj)
            if meta.__cs2lua_typeargs and meta.__cs2lua_typekinds then
                if meta.__cs2lua_typekinds[2] == TypeKind.Struct then
                    local vt = meta.__cs2lua_typeargs[2]
                    if vt==System.Int32 or vt==System.UInt32 
                        or vt==System.Int64 or vt==System.UInt64 
                        or vt==System.Char or vt==System.Byte 
                        or vt==System.Int16 or vt==System.UInt16 then
                        return false, 0
                    end
                end
            end
            return false, nil
        end,
    Clear = function(obj)
            __clear_table(obj)
        end,
    GetEnumerator = function(obj)
            return GetDictEnumerator(obj)
        end,
    GetType = function(obj)
            local meta = getmetatable(obj)
            return meta.__class
        end,
}

rawset(__mt_index_of_dictionary_table, "Remove__TKey", rawget(__mt_index_of_dictionary_table, "Remove"))

for k,v in pairs(__mt_index_of_dictionary_table) do
    rawset(System.Collections.Generic.Dictionary_TKey_TValue, k, v)
end

__mt_index_of_dictionary = function(t, k)
    if k == "Count" then
        return __get_table_count(t)
    elseif k == "Keys" then
        local meta = getmetatable(t)
        if not meta.cachedKeyCollection then
            meta.cachedKeyCollection = NewKeyCollection(t)
        end
        return meta.cachedKeyCollection
    elseif k == "Values" then
        local meta = getmetatable(t)
        if not meta.cachedValueCollection then
            meta.cachedValueCollection = NewValueCollection(t)
        end
        return meta.cachedValueCollection
    else 
        local f = __mt_index_of_dictionary_table[k]
        if f then
            return f
        else
            uk = __unwrap_if_string(k) 
            local data = __get_table_data(t)     
            local v = rawget(data, uk)
            if v then
                return v.Value
            end
            return nil
        end
    end
end

__mt_newindex_of_dictionary = function(t, k, val) 
    uk = __unwrap_if_string(k) 
    local data = __get_table_data(t)     
    local v = rawget(data, uk)
    if not v then
        rawset(data, uk, {Key = k, Value = val})
        __inc_table_count(t)
    else
        v.Value = val;
    end
end

__mt_index_of_hashset_table = {
    get_Count = function(obj)
             return __get_table_count(obj) 
        end,
    Add = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            rawset(data, up, true)
            __inc_table_count(obj)
            return true
        end,
    AddRange = function(obj, coll)
            local data = __get_table_data(obj)    
            local iter = newiterator(nil, coll)
            for v in getiterator(iter) do
                v = __unwrap_if_string(v)
                v = __get_hash_code_if_integer64(v)
                rawset(data, v, true)
                __inc_array_count(obj)
            end
            recycleiterator(nil, iter)
        end,    
    Remove = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            local ret = rawget(data, up)
            if ret then
                rawset(data, up, nil)
            end
            __dec_table_count(obj)
            return ret
        end,
    Contains = function(obj, p)
            up = __unwrap_if_string(p) 
            local data = __get_table_data(obj)     
            if rawget(data, up) then
                return true
            end
            return false
        end,
    CopyTo = function(obj, arr) 
            local data = __get_table_data(obj)     
            for k, v in pairs(data) do
                table.insert(arr, k)
                __inc_array_count(arr)
            end
        end,
    Clear = function(obj)
            __clear_table(obj)
        end,
    GetEnumerator = function(obj)
            return GetHashsetEnumerator(obj)
        end,
    GetType = function(obj)
            local meta = getmetatable(obj)
            return meta.__class
        end,
}

rawset(__mt_index_of_hashset_table, "CopyTo__A_T", rawget(__mt_index_of_hashset_table, "CopyTo"))
rawset(__mt_index_of_hashset_table, "CopyTo__A_T__Int32", rawget(__mt_index_of_hashset_table, "CopyTo"))
rawset(__mt_index_of_hashset_table, "CopyTo__A_T__Int32__Int32", rawget(__mt_index_of_hashset_table, "CopyTo"))

for k,v in pairs(__mt_index_of_hashset_table) do
    rawset(System.Collections.Generic.HashSet_T, k, v)
end

__mt_index_of_hashset = function(t, k)
    if k == "Count" then
        return __get_table_count(t)
    else
        return __mt_index_of_hashset_table[k]
    end
end

__mt_index_of_keycollection_table = {
    CopyTo = function(obj, arr) 
        local t = obj.dict
        local data = __get_table_data(t)     
        for k, v in pairs(data) do
            table.insert(arr, k)
            __inc_array_count(arr)
        end
    end,
    GetEnumerator = function(obj)
        return GetDictKeyEnumerator(obj)
    end,
}

__mt_index_of_keycollection = function(t, k)
    if k == "Count" then
        return t.dict.Count
    else
        return __mt_index_of_keycollection_table[k]
    end
end

function NewKeyCollection(dict)
    return setmetatable({
        dict = dict
    },
    {
        __index = __mt_index_of_keycollection,
        __cs2lua_defined = true,
    })
end

__mt_index_of_valuecollection_table = {
    CopyTo = function(obj, arr) 
        local t = obj.dict
        local data = __get_table_data(t)     
        for k, v in pairs(data) do
            table.insert(arr, v.Value)
            __inc_array_count(arr)
        end
    end,
    GetEnumerator = function(obj)
        return GetDictValueEnumerator(obj)
    end,
}

__mt_index_of_valuecollection = function(t, k)
    if k == "Count" then
        return t.dict.Count
    else
        return __mt_index_of_valuecollection_table[k]
    end
end

function NewValueCollection(dict)
    return setmetatable({
        dict = dict
    },
    {
        __index = __mt_index_of_valuecollection,
        __cs2lua_defined = true,
    })
end

function GetArrayEnumerator(tb)
    local function __get_Current(obj) return obj.current end
    return setmetatable(
        {
            Reset = function(this)
                this.index = 0
                this.current = nil
            end,
            MoveNext = function(this)
                local ltb = this.object
                local num = __get_array_count(ltb)
                if this.index < num then
                    this.index = this.index + 1
                    this.current = rawget(ltb, this.index)
                    return true
                else
                    return false
                end
            end,
            object = tb,
            index = 0,
            current = nil
        },
        {
            __index = function(t, k)
                if k == "Current" then
                    return t.current
                elseif k == "get_Current" then
                    return __get_Current
                end
                return nil
            end
        }
    )
end

function GetDictEnumerator(tb)
    local function __get_Current(obj) return obj.current end
    return setmetatable(
        {
            Reset = function(this)
                this.key = nil
                this.current = nil
            end,
            MoveNext = function(this)
                local ltb = this.object
                local v = nil 
                local data = __get_table_data(ltb)     
                this.key, v = next(data, this.key)
                this.current = v
                if this.key then
                    return true
                else
                    return false
                end
            end,
            object = tb,
            key = nil,
            current = nil
        },
        {
            __index = function(t, k)
                if k == "Current" then
                    return t.current
                elseif k == "get_Current" then
                    return __get_Current
                end
                return nil
            end
        }
    )
end

function GetDictKeyEnumerator(tb)
    local function __get_Current(obj) return obj.current end
    return setmetatable(
        {
            Reset = function(this)
                this.key = nil
                this.current = nil
            end,
            MoveNext = function(this)
                local ltb = this.object
                local v = nil 
                local data = __get_table_data(ltb)     
                this.key, v = next(data, this.key)
                this.current = this.key
                if this.key then
                    return true
                else
                    return false
                end
            end,
            object = tb.dict,
            key = nil,
            current = nil
        },
        {
            __index = function(t, k)
                if k == "Current" then
                    return t.current
                elseif k == "get_Current" then
                    return __get_Current
                end
                return nil
            end
        }
    )
end

function GetDictValueEnumerator(tb)
    local function __get_Current(obj) return obj.current end
    return setmetatable(
        {
            Reset = function(this)
                this.key = nil
                this.current = nil
            end,
            MoveNext = function(this)
                local ltb = this.object
                local v = nil 
                local data = __get_table_data(ltb)     
                this.key, v = next(data, this.key)
                this.current = v and v.Value
                if this.key then
                    return true
                else
                    return false
                end
            end,
            object = tb.dict,
            key = nil,
            current = nil
        },
        {
            __index = function(t, k)
                if k == "Current" then
                    return t.current
                elseif k == "get_Current" then
                    return __get_Current
                end
                return nil
            end
        }
    )
end

function GetHashsetEnumerator(tb)
    local function __get_Current(obj) return obj.Key end
    return setmetatable(
        {
            Reset = function(this)
                this.key = nil
            end,
            MoveNext = function(this)
                local ltb = this.object
                local v = nil 
                local data = __get_table_data(ltb)     
                this.key, v = next(data, this.key)
                if this.key then
                    return true
                else
                    return false
                end
            end,
            object = tb,
            key = nil
        },
        {
            __index = function(t, k)
                if k == "Current" then
                    return t.key
                elseif k == "get_Current" then
                    return __get_Current
                end
                return nil
            end
        }
    )
end

function newiterator(funcInfo, exp)
    local meta = getmetatable(exp)
    if meta and rawget(meta, "__cs2lua_defined") then
        if meta.cachedIters and meta.cachedIters[exp] and #(meta.cachedIters[exp])>0 then
            local iterInfo = table.remove(meta.cachedIters[exp], 1)
            iterInfo[2]:Reset()
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        else
            local enumer = exp:GetEnumerator()
            local f = function()
                if enumer:MoveNext() then
                    local v = enumer.Current
                    if v == nil then
                        v = __cs2lua_nil
                    end
                    return v
                else
                    return nil
                end
            end
            local iterInfo = {f, enumer, exp}            
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        end
    elseif meta and rawget(meta, "__typename")=="LuaArray" then
        --lualog("LuaArray newiterator:{0} {1}", exp, exp.Length)
        --printStack()
        if meta.cachedIters and meta.cachedIters[exp] and #(meta.cachedIters[exp])>0 then
            local iterInfo = table.remove(meta.cachedIters[exp], 1)
            iterInfo[2]()  
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        else
            local arr = exp
            local curIx = 0
            local f = function()
                --lualog("LuaArray iterator arr:{0} length:{1}", arr, arr.Length)
                if curIx < arr.Length then
                    curIx = curIx + 1
                    local v = arr[curIx]
                    --lualog("LuaArray iterator:{0} {1}", curIx, v)
                    if v == nil then
                        v = __cs2lua_nil
                    end
                    return v
                else
                    --lualog("LuaArray iterator:{0} nil", curIx)
                    return nil
                end
            end
            local reset = function()
                curIx = 0
            end
            local iterInfo = {f, reset, exp}      
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        end
    else
        if meta and meta.cachedIters and meta.cachedIters[exp] and #(meta.cachedIters[exp])>0 then
            local iterInfo = table.remove(meta.cachedIters[exp], 1)
            iterInfo[1](true) 
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        else
            local iterInfo = {Slua.iter(exp), true, exp} 
            if funcInfo then
                table.insert(funcInfo.iter_list, iterInfo)
            end
            return iterInfo
        end   
    end
end

function getiterator(iterInfo)
    return iterInfo[1]
end

function recycleiterator(funcInfo, iterInfo)
    if funcInfo then
        luatableremove(funcInfo.iter_list, iterInfo)
    end
    local exp = iterInfo[3]
    if exp then
        local meta = getmetatable(exp)
        if meta then
            if meta.cachedIters then
                if not meta.cachedIters[exp] then
                    meta.cachedIters[exp] = {}
                end
                table.insert(meta.cachedIters[exp], iterInfo)
            else
                meta.cachedIters = {}
                meta.cachedIters[exp] = {iterInfo}
            end
        end
    end
end

function wraparray(arr, size, classObj, typeKind)
    if not size then
        size = #arr
    end
    return setmetatable(
        arr,
        {
            __index = __mt_index_of_array,
            __count = size,
            __cs2lua_defined = true,
            __class = System.Collections.Generic.List_T
        }
    )
end

function newarraydim0(classObj, typeKind, defVal)
    error("illegal array !")
end

function newarraydim1(classObj, typeKind, defVal, size1)
    local arr = wraparray({}, size1, classObj, typeKind)
    for i = 1,size1 do
        arr[i] = defVal
    end
    return arr
end

function newarraydim2(classObj, typeKind, defVal, size1, size2)
    local arr = wraparray({}, size1, classObj, typeKind)
    for i = 1,size1 do
        arr[i] = wraparray({}, size2, classObj, typeKind)
        for j = 1,size2 do
            arr[i][j] = defVal
        end
    end
    return arr
end

function newarraydim3(classObj, typeKind, defVal, size1, size2, size3)
    local arr = wraparray({}, size1, classObj, typeKind)
    for i = 1,size1 do
        arr[i] = wraparray({}, size2, classObj, typeKind)
        for j = 1,size2 do
            arr[i][j] = wraparray({}, size3, classObj, typeKind)
            for k = 1,size3 do
                arr[i][j][k] = defVal
            end
        end
    end
    return arr
end

function wrapanonymousobject(dict)
    local obj = {}
    setmetatable(
        obj,
        {
            __index = __mt_index_of_dictionary,
            __newindex = __mt_newindex_of_dictionary,
            __cs2lua_defined = true,
            __class = System.Collections.Generic.Dictionary_TKey_TValue,
            __cs2lua_data = {}
        }
    )
    for k, v in pairs(dict) do
        obj:Add(k, v)
    end
    return obj
end

function wrapparams(arr, elementType, elementTypeKind)
    return wraparray(arr, nil, elementType, elementTypeKind)
end

function newdictionary(t, typeargs, typekinds, ctor, ctorRetCt, dict, ...)
    if dict then
        local obj = {}
        setmetatable(
            obj,
            {
                __index = __mt_index_of_dictionary,
                __newindex = __mt_newindex_of_dictionary,
                __cs2lua_defined = true,
                __class = t,
                __cs2lua_typeargs = typeargs,
                __cs2lua_typekinds = typekinds,
                __cs2lua_data = {}
            }
        )
        for k, v in pairs(dict) do
            obj:Add(k, v)
        end
        local arg1 = ...
        if arg1 and (type(arg1)=="table" or type(arg1)=="userdata") then
            local iter = newiterator(arg1)
            for v in getiterator(iter) do
                obj:Add(v.Key, v.Value)
            end        
        end
        return obj
    end
end

function newlist(t, typeargs, typekinds, ctor, ctorRetCt, list, ...)
    if list then
        local obj = setmetatable(list, {__index = __mt_index_of_array, __count = #list, __cs2lua_defined = true, __class = t})
        local arg1 = ...
        if arg1 and (type(arg1)=="table" or type(arg1)=="userdata") then
            --lualog("arg1:{0} {1}", arg1, type(arg1))
            local meta = getmetatable(arg1)
            if meta and not rawget(meta, "__cs2lua_defined") then
                local typename = rawget(meta, "__typename")
                if typename=="LuaArray" then
                    local ct = arg1.Length
                    for i = 1, ct do
                        obj:Add(arg1[i])
                    end
                end
            else
                obj:AddRange(arg1)                
            end
        end
        return obj
    end
end

function newcollection(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    if t == Cs2LuaList_T then
        return newlist(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    elseif t == Cs2LuaIntDictionary_TValue or t == Cs2LuaStringDictionary_TValue then
        return newdictionary(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    elseif coll then
        local obj = setmetatable({}, {__index = __mt_index_of_hashset, __cs2lua_defined = true, __class = t, __cs2lua_data = {}})
        for i, v in ipairs(coll) do
            obj:Add(v)
        end
        local arg1 = ...
        if arg1 and (type(arg1)=="table" or type(arg1)=="userdata") then
            --lualog("arg1:{0} {1}", arg1, type(arg1))
            local meta = getmetatable(arg1)
            if meta and not rawget(meta, "__cs2lua_defined") then
                local typename = rawget(meta, "__typename")
                if typename=="LuaArray" then
                    local ct = arg1.Length
                    for i = 1, ct do
                        obj:Add(arg1[i])
                    end
                end
            else
                obj:AddRange(arg1)                
            end
        end
        return obj
    end
end

function newexterndictionary(t, typeargs, typekinds, ctor, ctorRetCt, dict, ...)
    if dict and t == System.Collections.Generic.Dictionary_TKey_TValue then
        return newdictionary(t, typeargs, typekinds, ctor, ctorRetCt, dict, ...)
    else
        local obj = t[ctor](...)
        if obj then
            if dict ~= nil then
                for k, v in pairs(dict) do
                    obj:Add(k, v)
                end
            end
            return obj
        else
            return nil
        end
    end
end

function newexternlist(t, typeargs, typekinds, ctor, ctorRetCt, list, ...)
    if list and t == System.Collections.Generic.List_T then
        return newlist(t, typeargs, typekinds, ctor, ctorRetCt, list, ...)
    else
        local obj = t[ctor](...)
        if obj then
            if list ~= nil then
                for i, v in ipairs(list) do
                    obj:Add(v)
                end
            end
            return obj
        else
            return nil
        end
    end
end

function newexterncollection(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    if coll and (t == System.Collections.Generic.Queue_T or t == System.Collections.Generic.Stack_T) then
        return newlist(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    elseif coll and t == System.Collections.Generic.HashSet_T then
        return newcollection(t, typeargs, typekinds, ctor, ctorRetCt, coll, ...)
    else
        local obj = t[ctor](...)
        if obj then
            if coll ~= nil then
                for i, v in ipairs(coll) do
                    obj:Add(v)
                end
            end
            return obj
        else
            return nil
        end
    end
end

function lshift(v, n)
    if bit then
        return bit.lshift(v, n)
    else
        for i = 1, n do
            v = v * 2
        end
        return v
    end
end

function rshift(v, n)
    if bit then
        return bit.rshift(v, n)
    else
        for i = 1, n do
            v = v / 2
        end
        return v
    end
end

--tv与fv都是常量时使用
function simplecondexp(cv, tv, fv)
    if cv then
        return tv
    else
        return fv
    end
end

function condaccess(v, func)
    if v then
        return func()
    else
        return nil
    end
end

function nullcoalescing(v, func)
    if v then
        return v
    else
        return func()
    end
end

function bitnot(v)
    if bit then
        return bit.bnot(v)
    else
        return 0
    end
end

function bitand(v1, v2)
    if v1==true and v2==true then
        return true
    elseif v1==false and v2==false then
        return false
    elseif v1==true and v2==false then
        return false
    elseif v1==false and v2==true then
        return false
    end
    if bit then
        return bit.band(v1, v2)
    else
        return 0
    end
end

function bitor(v1, v2)
    if v1==true and v2==true then
        return true
    elseif v1==false and v2==false then
        return false
    elseif v1==true and v2==false then
        return true
    elseif v1==false and v2==true then
        return true
    end
    if bit then
        return bit.bor(v1, v2)
    else
        return 0
    end
end

function bitxor(v1, v2)
    if bit then
        return bit.bxor(v1, v2)
    else
        return 0
    end
end

LINQ = {}
LINQ.exec = function(linq)
    local paramList = {}
    local ix = 1
    return LINQ.execRecursively(linq, ix, paramList)
end
LINQ.execRecursively = function(linq, ix, paramList)
    local finalRs = {}
    local interRs = {}
    local itemNum = #linq
    while ix <= itemNum do
        local v = linq[ix]
        local key = v[1]
        ix = ix + 1

        if key == "from" then
            local nextIx = LINQ.getNextIndex(linq, ix)

            --获取目标集合
            local coll = v[2](unpack(paramList))
            LINQ.buildIntermediateResult(linq, ix, paramList, coll, interRs, finalRs)

            ix = nextIx
        elseif key == "where" then
            --在中间结果集上进行过滤处理
            local temp = interRs
            interRs = {}
            for i, val in ipairs(temp) do
                if v[2](unpack(val)) then
                    table.insert(interRs, val)
                end
            end
        elseif key == "orderby" then
            --排序（多关键字）
            table.sort(
                interRs,
                (function(l1, l2)
                    return LINQ.compare(l1, l2, v[2])
                end)
            )
        elseif key == "select" then
            --生成最终结果集
            for i, val in ipairs(interRs) do
                local r = v[2](unpack(val))
                table.insert(finalRs, r)
            end
        else
            --其它子句暂不支持。。
        end
    end
    return finalRs
end
LINQ.buildIntermediateResult = function(linq, ix, paramList, coll, interRs, finalRs)
    --遍历目标集合，处理连续的let与where (这时where条件可以在单个元素遍历时进行，不用等中间结果集构建后再过滤)
    --如果又遇到from，则递归调用自身来获取子集并合并到当前结果集
    for cv in getiterator(coll) do
        local newParamList = {unpack(paramList)}
        table.insert(newParamList, cv)
        local isMatch = true
        local newIx = ix
        local itemNum = #linq
        while newIx <= itemNum do
            local v = linq[newIx]
            local key = v[1]

            if key == "let" then
                table.insert(newParamList, v[2](unpack(newParamList)))
            elseif key == "where" then
                if not v[2](unpack(newParamList)) then
                    --不符合条件的记录不放到中间结果集
                    isMatch = false
                    break
                end
            elseif key == "from" then
                --再次遇到from，递归调用再合并结果集
                local ts = LINQ.execRecursively(linq, newIx, newParamList)
                for i, val in ipairs(ts) do
                    table.insert(finalRs, val)
                end
                isMatch = false
                break
            else
                --其它子句需要在中间结果集完成后再处理，这里跳过
                break
            end
            newIx = newIx + 1
        end
        if isMatch then
            table.insert(interRs, newParamList)
        end
    end
end
LINQ.compare = function(l1, l2, list)
    for i, v in ipairs(list) do
        local v1 = v[1](unpack(l1))
        local v2 = v[1](unpack(l2))
        local asc = v[2]
        if v1 ~= v2 then
            if asc then
                return v1 < v2
            else
                return v1 > v2
            end
        end
    end
    return true
end
LINQ.getNextIndex = function(linq, ix)
    local itemNum = #linq
    while ix <= itemNum do
        local v = linq[ix]
        local key = v[1]
        if key == "let" then
        elseif key == "where" then
        elseif key == "from" then
            return itemNum + 1
        else
            return ix
        end
        ix = ix + 1
    end
    return ix
end

function warmup(class)
    local ret = true
    if rawget(class, "__cs2lua_predefined") and not rawget(class, "__cs2lua_defined") then
        ret = class.__cs2lua_defined
    end
    return ret
end

function getobjfullname(obj)
    local ty = type(obj)
    if ty == "string" then
        return "System.String"
    elseif ty == "number" then
        return "System.Double"
    end
    local meta = getmetatable(obj)
    if meta then
        if rawget(meta, "__cs2lua_defined") then
            return rawget(meta, "__cs2lua_fullname")
        else
            local name = rawget(meta, "__fullname")
            local ix = string.find(name, ",")
            if ix == nil then
                return name
            else
                return string.sub(name, 1, ix - 1)
            end
        end
    else
        return nil
    end
end

function getobjtypename(obj)
    local ty = type(obj)
    if ty == "string" then
        return "System.String"
    elseif ty == "number" then
        return "System.Double"
    end
    local meta = getmetatable(obj)
    if meta then
        if rawget(meta, "__cs2lua_defined") then
            return rawget(meta, "__cs2lua_typename")
        else
            return rawget(meta, "__typename")
        end
    else
        return nil
    end
end

function getclassfullname(t)
    if t and type(t) ~= "string" then
        if type(t) ~= "table" then
            return tostring(t)
        elseif t == System.Type then
            return t.FullName
        else
            warmup(t)
            if rawget(t, "__cs2lua_defined") then
                return rawget(t, "__cs2lua_fullname")
            else
                local meta = getmetatable(t)
                if meta then
                    local name = rawget(meta, "__fullname")
                    local ix = string.find(name, ",")
                    if ix == nil then
                        return name
                    else
                        return string.sub(name, 1, ix - 1)
                    end
                else
                    return nil
                end
            end
        end
    else
        return t
    end
end

function getclasstypename(t)
    if t and type(t) ~= "string" then
        if type(t) ~= "table" then
            return tostring(t)
        elseif t == System.Type then
            return t.Name
        else
            warmup(t)
            if rawget(t, "__cs2lua_defined") then
                return rawget(t, "__cs2lua_typename")
            else
                local meta = getmetatable(t)
                if meta then
                    return rawget(meta, "__typename")
                else
                    return nil
                end
            end
        end
    else
        return t
    end
end

function getobjparentclass(obj)
    local ty = type(obj)
    if ty == "string" or ty == "number" then
        return nil
    end
    local meta = getmetatable(obj)
    if meta then
        if rawget(meta, "__cs2lua_defined") then
            return rawget(meta, "__cs2lua_parent")
        else
            return rawget(meta, "__parent")
        end
    else
        return nil
    end
end

function getclassparentclass(t)
    if t and type(t) ~= "string" then
        if type(t) ~= "table" then
            return tostring(t)
        else
            warmup(t)
            if rawget(t, "__cs2lua_defined") then
                return rawget(t, "__cs2lua_parent")
            else
                return rawget(t, "__parent")
            end
        end
    else
        return nil
    end
end

function typecast(obj, t, tk)
    if t == System.String then
        return tostring(obj)
    elseif t == System.Single or t == System.Double then
        return tonumber(obj)
    elseif t == System.Int64 or t == System.UInt64 then
        local v = tonumber(obj)
        v = math.floor(v)
        return v
    elseif t == System.Int32 or t == System.UInt32 then
        local v = tonumber(obj)
        v = math.floor(v)
        if v > 0 then
            v = v % 0x100000000
        elseif v < 0 then
            v = -((-v) % 0x100000000)
        end
        if t == System.Int32 and v > 0x7fffffff then
            v = v - 0xffffffff - 1
        end
        return v
    elseif t == System.Int16 or t == System.UInt16 or t == System.Char then
        local v = tonumber(obj)
        v = math.floor(v)
        if v > 0 then
            v = v % 0x10000
        elseif v < 0 then
            v = -((-v) % 0x10000)
        end
        if t == System.Int16 and v > 0x7fff then
            v = v - 0xffff - 1
        end
        return v
    elseif t == System.SByte or t == System.Byte then
        local v = tonumber(obj)
        v = math.floor(v)
        if v > 0 then
            v = v % 0x100
        elseif v < 0 then
            v = -((-v) % 0x100)
        end
        if t == System.SByte and v > 0x7f then
            v = v - 0xff - 1
        end
        return v
    elseif t == System.Boolean then
        return obj
    elseif tk == TypeKind.Enum then
        return obj
    elseif typeis(obj, t, tk) then
        return obj
    else
        return obj
    end
end

function typeas(obj, t, tk)
    if t == System.String then
        return tostring(obj)
    elseif t == System.Single or t == System.Double then
        return tonumber(obj)
    elseif t == System.Int64 or t == System.UInt64 then
        local v = tonumber(obj)
        v = math.floor(v)
        return v
    elseif t == System.Int32 or t == System.UInt32 then
        return typecast(obj, t, tk)
    elseif t == System.Int16 or t == System.UInt16 or t == System.Char then
        return typecast(obj, t, tk)
    elseif t == System.SByte or t == System.Byte then
        return typecast(obj, t, tk)
    elseif t == System.Boolean then
        return obj
    elseif tk == TypeKind.Enum then
        return obj
    elseif typeis(obj, t, tk) then
        return obj
    elseif tk == TypeKind.Delegate then
        return obj
    else
        return nil
    end
end

function typeis(obj, t, tk)
    if obj == nil then
        return false
    end
    local meta = getmetatable(obj)
    local tn1 = getobjfullname(obj)
    local tn2 = getclassfullname(t)
    if meta then
        if meta.__class == System.Collections.Generic.List_T and t == System.Array then
            return true
        end
        if type(obj) == "userdata" then
            if tn1 and tn1 == tn2 then
                return true
            end
            --check slua parent metatable chain
            local parent = rawget(meta, "__parent")
            while parent ~= nil do
                tn1 = rawget(parent, "__fullname")
                if tn1 and tn1 == tn2 then
                    return true
                end
                parent = rawget(parent, "__parent")
            end
        else
            if rawget(meta, "__class") == t then
                return true
            end
            local intfs = rawget(meta, "__interfaces")
            if intfs then
                for i, v in ipairs(intfs) do
                    if v == tn2 then
                        return true
                    end
                end
            end
            --check cs2lua base class chain
            local baseClass = rawget(meta, "__cs2lua_parent")
            local lastCheckedClass = meta
            while baseClass ~= nil do
                if baseClass == t then
                    return true
                end
                intfs = rawget(meta, "__interfaces")
                if intfs then
                    for i, v in ipairs(intfs) do
                        if v == tn2 then
                            return true
                        end
                    end
                end
                if rawget(baseClass, "__cs2lua_defined") then
                    baseClass = rawget(baseClass, "__cs2lua_parent")
                else
                    lastCheckedClass = baseClass
                    break
                end
            end
            --try slua base class and parent metatable chain
            if not rawget(lastCheckedClass, "__cs2lua_defined") then
                local meta3 = getmetatable(lastCheckedClass)
                if meta3 then
                    parent = rawget(meta3, "__parent")
                    while parent ~= nil do
                        tn1 = rawget(parent, "__fullname")
                        if tn1 and tn1 == tn2 then
                            return true
                        end
                        parent = rawget(parent, "__parent")
                    end
                end
            end
        end
    end
    if tk == TypeKind.Delegate and type(obj) == "function" then
        return true
    end
    return false
end

function __do_eq(v1, v2)
    return v1 == v2
end

function isequal(v1, v2)
    local succ, res = pcall(__do_eq, v1, v2)
    if succ then
        return res
    else
        return rawequal(v1, v2)
    end
end

function stringisequal(v1, v2)
    if v1==nil or v2==nil then
        return v1==v2
    elseif type(v1)=="string" and type(v2)=="string" then
        return v1==v2
    else
        local r = tostring(v1)==tostring(v2)
        --lualog("[debug] stringisequal [{0}],[{1}] {2}", v1, v2, r)
        --printStack()
        return r
    end
end

function __unwrap_if_string(val)
    return csstrtoluastr(val)
end

function __find_extern_class_or_obj_key(k, obj)
    local t=getmetatable(obj)
    repeat
        local fun=rawget(t,k)
        local tp=type(fun)        
        if tp=='function' then 
            return true 
        elseif tp=='table' then
            local f=fun[1]
            if f then
                return true
            end
        end
        t = rawget(t,'__parent')
    until t==nil
    return false
end
function __find_extern_obj_member(k, obj)
    local t=getmetatable(obj)
    repeat
        local fun=rawget(t,k)
        local tp=type(fun)        
        if tp=='function' then 
            return tp() 
        elseif tp=='table' then
            local f=fun[1]
            if f then
                return f()
            end
        end
        t = rawget(t,'__parent')
    until t==nil
    return false
end

function wrapvirtual(k, f, class)
    return function(this, ...)
        return this[k](this, ...)
    end
end
function wrapabstract(k, class)
    return function(this, ...)
        return this[k](this, ...)
    end
end

function defineclass(
    base,
    fullName,
    typeName,
    class,    
    obj_methods,
    is_value_type,
    is_inherit_csharp)
        
    local base_class = base
    
    local class_fields = rawget(class, "__class_fields")
    local obj_fields = nil
    local obj_field_values = nil

    local interfaces = rawget(class, "__interfaces")
    local method_info = rawget(class, "__method_info")
    local is_sealed_class = rawget(class, "__is_sealed_class")
    local is_static_class = rawget(class, "__is_static_class")

    local function __get_obj_methods(fk)
        return obj_methods
    end
    local function __obj_GetType(tb)
        return class
    end
    
    rawset(class, "__cs2lua_defined", true)
    rawset(class, "__cs2lua_fullname", fullName)
    rawset(class, "__cs2lua_typename", typeName)
    rawset(class, "__cs2lua_parent", base_class)
    rawset(class, "__is_value_type", is_value_type)
    rawset(class, "__interfaces", interfaces)
    
    rawset(class, "FullName", fullName)
    rawset(class, "Name", typeName)
    rawset(class, "__get_obj_methods", __get_obj_methods)
    if not obj_methods then
        obj_methods = {}
    end
    rawset(obj_methods, "GetType", __obj_GetType)
    
    --合并基类字段信息
    if base_class then
        obj_fields = {}
        local curClass = class
        while nil~=curClass do
            if warmup(curClass) then
                local ofs = rawget(curClass, "__obj_fields")
                if ofs then
                    for k,v in pairs(ofs) do
                        rawset(obj_fields, k, v)
                    end
                end
            else
                break
            end
            curClass = rawget(curClass, "__cs2lua_parent")
        end
        if rawget(base_class, "__get_obj_methods") then
            rawset(obj_methods, "__index", base_class.__get_obj_methods())
            setmetatable(obj_methods, obj_methods)
        end
    else
        obj_fields = rawget(class, "__obj_fields")
    end
    
    local function obj_build()
        local obj = {}
        if base_class then
            local curClass = class
            while nil~=curClass do
                if warmup(curClass) then
                    local init_obj_fields = rawget(curClass, "__init_obj_fields")
                    if init_obj_fields then
                        init_obj_fields(obj)
                    end
                else
                    break
                end
                curClass = rawget(curClass, "__cs2lua_parent")
            end
        else
            local init_obj_fields = rawget(class, "__init_obj_fields")
            if init_obj_fields then
                init_obj_fields(obj)
            end
        end
        return obj
    end
    
    local obj_meta = {
        __class = class,
        __cs2lua_defined = true,
        __cs2lua_fullname = fullName,
        __cs2lua_typename = typeName,
        __cs2lua_parent = base_class,
        __is_value_type = is_value_type,
        __interfaces = interfaces,
        
        __index = obj_methods,
    }

    if is_inherit_csharp then
        rawset(obj_meta, "__index", function(t, k)
                if obj_fields then
                    local ret = obj_fields[k]
                    if nil ~= ret then
                        --是当前类字段但仍走到元方法里了，则表明当前字段值为空
                        return nil
                    end
                end
                local f = obj_methods[k]
                if f then
                    return f
                end
                local baseObj = rawget(t, "__base")
                if baseObj and __find_extern_class_or_obj_key(k, baseObj) then
                    return __find_extern_obj_member(k, baseObj)
                end
                lualog("lookup meta for {0}.{1} base_class {2} baseObj {3}", t:GetType().FullName, k, base_class and base_class.FullName, baseObj)
                printStack()
                return nil
            end)
        rawset(obj_meta, "__newindex", function(t, k, v)
                if obj_fields then
                    local ret = obj_fields[k]
                    if nil ~= ret then
                        rawset(t, k, v)
                        return
                    end
                end
                local baseObj = rawget(t, "__base")
                if baseObj and __find_extern_class_or_obj_key(k, baseObj) then
                    baseObj[k] = v
                    return
                end
            end)
    end
    
    if base_class then
        rawset(class, "__index", base_class)
        rawset(class, "__newindex", function(t, k, v)
                if class_fields then
                    local ret = class_fields[k]
                    if nil ~= ret then
                        rawset(t, k, v)
                        return
                    end
                end
                base_class[k] = v
            end)
    end
    rawset(class, "__call", function(t)
            local obj = obj_build()
            setmetatable(obj, obj_meta)
            return obj
        end)
    setmetatable(class, class)
    if rawget(class, "cctor") then
        class.cctor()
    end
        
    return class
end


function getoriginalmethod(class, name)
    local obj_methods = class.__get_obj_methods()
    return obj_methods[name]
end

function buildbaseobj(obj, class, baseClass, baseCtor, baseCtorRetCt, ...)
    rawset(obj, "__base", nil)
    getoriginalmethod(baseClass, baseCtor)(obj, ...)
    rawset(obj, "__ctor_called", false)
end

function buildexternbaseobj(obj, class, baseClass, baseCtor, baseCtorRetCt, ...)
    local baseObj = nil
    if base_class == UnityEngine.MonoBehaviour then
        baseObj = nil
    else
        baseObj = baseClass[baseCtor](...)
    end
            
    rawset(obj, "__base", baseObj)
end

--这个函数仅用于翻译的lua代码，用于处理base.field的语法
function getbaseobj(obj)
    local base = rawget(obj, "__base") 
    if base then
        return base
    else
        return obj
    end
end

function defineentry(class)
    _G.main = function()
        return class
    end
end

function getglobalinfo(key)
    return rawget(_G, key)
end
function buildglobalinfoonce(key, val)
    local old = rawget(_G, key)
    if old~=val then
        rawset(_G, key, val)
    end
    return val
end

function newstruct(class, typeargs, typekinds, ctor, ctorRetCt, initializer, ...)
    local obj = class()
    if ctor then
        class[ctor](obj, ...)
    end
    translationlog("need add handler for newstruct {0}", getclasstypename(class))
    if obj and initializer then
        initializer(obj)
    end
    return obj
end

function newexternstruct(class, typeargs, typekinds, ctor, ctorRetCt, initializer, ...)
    local obj = nil
    local arg1,arg2 = ...
    if class == System.Nullable_T then
        return nil
    elseif class == System.Collections.Generic.KeyValuePair_TKey_TValue then
        return {Key = arg1, Value = arg2}
    end
    translationlog("need add handler for newexternstruct {0}", getclasstypename(class))
    obj = class[ctor](...)
    if obj and initializer then
        initializer(obj)
    end
    return obj
end

function newobject(class, typeargs, typekinds, ctor, ctorRetCt, initializer, ...)
    local obj = class()
    if ctor then
        class[ctor](obj, ...)
    end
    if obj and initializer then
        initializer(obj)
    end
    return obj
end

function newexternobject(class, typeargs, typekinds, ctor, ctorRetCt, initializer, ...)
    local obj = nil
    local arg1,arg2 = ...
    if class == System.Nullable_T then
        return nil
    elseif class == System.Collections.Generic.KeyValuePair_TKey_TValue then
        return {Key = arg1, Value = arg2}
    end
    obj = class[ctor](...)
    if obj and initializer then
        initializer(obj)
    end
    return obj
end

function newtypeparamobject(t)
    local obj = nil
    warmup(t)
    if rawget(t, "__cs2lua_defined") then
        obj = t()
        if t.ctor then
            t.ctor(obj)
        end
    elseif t.ctor then
        obj = t.ctor()
    else
        obj = t()
    end
    return obj
end

function defaultvalue(t, typename, isExtern)
    if t == UnityEngine.Vector3 then
        return UnityEngine.Vector3.zero
    elseif t == UnityEngine.Vector2 then
        return UnityEngine.Vector2.zero
    elseif t == UnityEngine.Vector4 then
        return UnityEngine.Vector4.zero
    elseif t == UnityEngine.Quaternion then
        return UnityEngine.Quaternion.identity
    elseif t == UnityEngine.Color then
        return UnityEngine.Color.black
    elseif t == UnityEngine.Color32 then
        return UnityEngine.Color32.ctor()
    elseif isExtern and t then
        return t.ctor()
    elseif t and t.__is_value_type then
        return t.__new_object()
    else
        return nil
    end
end

require "lualib_valuetypescript"
require "lualib_basic"
require "lualib_special"
