XLua 遍历C# List或Dictionary元素以及pairs和ipairs

这一篇主要讲讲如何在lua中遍历List<>或者Dictionary<>的对象。

起因是在XLua官方讨论群里面正好有人问了怎么遍历,然后官方人员说使用for k,v in pairs(要遍历对象) do ... end就可以了。自己就顺手去试了试,结果发现一直报错,纠结了大半天,就在这儿记录一下。最后问了官方的人,结果是因为XLua不是最新的版本,心里苦啊。所有大家一定要更新好XLua,否则可能和我一样会遇到下面这些错误:

 bad argument #1 to 'for iterator' (table expected, got System.Collections.Generic.List`1


遍历

需求

接着就说说如何实现XLua中遍历C#的List或Dictionary,首先我们先定义好需要遍历的测试对象,如下。

public class Fu {
    public List GetList() {
        List l = new List();
        l.Add(1);
        l.Add(3);
        l.Add(7);
        l.Add(6);
        l.Add(0);
        return l;
    }

    public List GetSList() {
        List l = new List();
        l.Add("aa");
        l.Add("sdf");
        l.Add("wer");
        l.Add("rr");
        l.Add("w3");
        return l;
    }

    public Dictionary GetDic() {
        Dictionary dic = new Dictionary();
        dic.Add(100, "ad");
        dic.Add(103, "ewq");
        dic.Add(140, "2s");
        dic.Add(600, "fs");
        return dic;
    }
}

方法一

接着我们即可在Lua中实现对应的遍历,方法都是一样的(for k,v in pairs(list) do then),如下:

--获取对应的List
local fu = CS.Fu();
local list = fu:GetList();
local slist = fu:GetSList();
local dic = fu:GetDic();

--遍历
for k,v in pairs(list) do
	print('List---'..k..'--'..v);
end

print('============================');
for k,v in pairs(slist) do
	print('List---'..k..'--'..v);
end

print('============================');
for k,v in pairs(dic) do
	print('Dictionary---'..k..'--'..v);
end

打印的Log如下

XLua 遍历C# List或Dictionary元素以及pairs和ipairs_第1张图片


方法二

当然除了上述的方法(类似c#的foreach)我们还可以用下面的方法来遍历(类似c#的for):

for i = 0, 4 do
    print(list[i]);
end

方法三

如果XLua版本不升级的也可以在C#端给List,Dictionary做一层封装,将其转换成LuaTable,然后再用第一种方法去遍历。


补充

关于Lua中的for循环以及上诉用到pairs方法,在官方文档都有描述,这里贴一份(Lua5.3)

for

for 有两种形式:一种是数字形式,另一种是通用形式。

数字形式的 for 循环,通过一个数学运算不断地运行内部的代码块。 下面是它的语法:

stat ::= for Name ‘=’ exp ‘,’ exp [‘,’ exp] do block end

block 将把 name 作循环变量。 从第一个 exp 开始起,直到第二个 exp 的值为止, 其步长为第三个 exp 。 更确切的说,一个for 循环看起来是这个样子

for v = e1, e2, e3 do block end

这等价于代码:

do
	local var, limit, step = tonumber(e1), tonumber(e2), tonumber(e3)
	if not (var and limit and step) then error() end
	var = var - step
	while true do
		var = var + step
		if (step >= 0 and var > limit) or (step < 0 and var < limit) then
			break
		end
		local v = var
	block
	end
end

注意下面这几点:

1.所有三个控制表达式都只被运算一次, 表达式的计算在循环开始之前。 这些表达式的结果必须是数字。

2.var,limit,以及 step 都是一些不可见的变量。 这里给它们起的名字都仅仅用于解释方便。

3.如果第三个表达式(步长)没有给出,会把步长设为 1 。

4.你可以用 break 和 goto 来退出 for 循环。

5.循环变量 v 是一个循环内部的局部变量; 如果你需要在循环结束后使用这个值, 在退出循环前把它赋给另一个变量。


通用形式的 for 通过一个叫作 迭代器 的函数工作。 每次迭代,迭代器函数都会被调用以产生一个新的值, 当这个值为 nil 时,循环停止。 通用形式的 for 循环的语法如下:

stat ::= for namelist in explist do block end

namelist ::= Name {‘,’ Name}

这样的 for 语句

for var_1, ···, var_n in explist do block end

它等价于这样一段代码:

do
	local f, s, var = explist
	while true do
		local var_1, ···, var_n = f(s, var)
		if var_1 == nil then break end
		var = var_1
		block
	end
end

注意以下几点:

1.explist 只会被计算一次。 它返回三个值, 一个 迭代器 函数, 一个 状态, 一个 迭代器的初始值。

2.f, s,与 var 都是不可见的变量。 这里给它们起的名字都只是为了解说方便。

3.你可以使用 break 来跳出 for 循环。

4.环变量 var_i 对于循环来说是一个局部变量; 你不可以在 for 循环结束后继续使用。 如果你需要保留这些值,那么就在循环跳出或结束前赋值到别的变量里去。


ipairs (t)

返回三个值(迭代函数、表 t 以及 0 ), 如此,以下代码

for i,v in ipairs(t) do body end

将迭代键值对(1,t[1]) ,(2,t[2]), ... ,直到第一个空值。

个人补充:使用这种方式遍历表,会从下标1开始读取对应的值(lua的table下标1起始),然后读取下标2,3...,当读到对应下标的值为nil时,就中断循环。同时忽略其他的下标,例如table['a']。

pairs (t)

如果 t 有元方法 __pairs, 以 t 为参数调用它,并返回其返回的前三个值。

否则,返回三个值:next 函数, 表 t,以及 nil。 因此以下代码

for k,v in pairs(t) do body end

能迭代表 t 中的所有键值对。

个人补充:这种方式遍历表,可以遍历表中所有的键值对。没有ipairs的那些约束,同时这种读取table并不是一种有序的读取。


因为纠结前面的问题的时候顺便也纠结了波pairs和ipairs的区别,注,上述遍历不能使用ipairs否则会报错

List:LuaException: c# exception:System.ArgumentOutOfRangeException: Argument is out of range.

List:LuaException: try to get System.Collections.Generic.List`1[System.String].Item throw a exception:System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.ArgumentOutOfRangeException: Argument is out of range.

Dictionary:LuaException: try to get System.Collections.Generic.Dictionary`2[System.Int32,System.String].Item throw a exception:System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.


关于两者的区分,直接例子说明(更多情况大家可以举例验证):

local table1 = {
	5,6,8,4
}

for k,v in pairs(table1) do
	print(k..'-'..v);
end
--打印结果为:1-5	2-6		3-8		4-4(有序)


print('============================');
for k,v in ipairs(table1) do
	print(k..'-'..v);
end
--打印结果为:1-5	2-6		3-8		4-4(有序,因为下标1,2,3,4全有,所以全部输出)





local table2 = {
	[1]=5,[3]=6,[4]=8,[5]=4
}


print('============================');
for k,v in pairs(table2) do
	print(k..'-'..v);
end
--打印结果为:4-8	1-5		5-4		3-6(乱序)


print('============================');
for k,v in ipairs(table2) do
	print(k..'-'..v);
end
--打印结果为:1-5(因为当读取下标2的值时为nil,中断循环)





local table3 = {
	['a']=5,['b']=6,['c']=8,['d']=4
}


print('============================');
for k,v in pairs(table3) do
	print(k..'-'..v);
end
--打印结果为:b-6	c-8		d-4		a-5(乱序)


print('============================');
for k,v in ipairs(table3) do
	print(k..'-'..v);
end
--打印结果为:无打印(因为当读取下标1的值时为nil,中断循环)


你可能感兴趣的:(XLua)