C# 获取数组长度的表达式

C# 获取数组长度的表达式,c#,arrays,expression-trees,cil,C#,Arrays,Expression Trees,Cil,如果您有一个数组类型的表达式,但不是int[]等特定数组类型的表达式,那么如何生成一个表达式,该表达式可以快速获取长度,而不必执行整个属性获取malarkay 例如,在下列情况下 ParameterExpression para3 = Expression.Parameter(typeof(int[]), "p3"); ParameterExpression para4 = Expression.Parameter(typeof(Array), "p4"); Type pt1 = para3.

如果您有一个数组类型的表达式,但不是int[]等特定数组类型的表达式,那么如何生成一个表达式,该表达式可以快速获取长度,而不必执行整个属性获取malarkay

例如,在下列情况下

ParameterExpression para3 = Expression.Parameter(typeof(int[]), "p3");
ParameterExpression para4 = Expression.Parameter(typeof(Array), "p4");

Type pt1 = para3.Type.GetElementType();
Type pt2 = para4.Type.GetElementType();

MethodInfo mArrayLength = Strong.Instance<Array>.Property<int>(a => a.Length).GetGetMethod();

Expression asdf5 = Expression.ArrayLength(para3);
Expression asdf6 = Expression.ArrayLength(para4);
Expression asdf7 = Expression.Call(para4, mArrayLength);
ParameterExpression para3=表达式.参数(typeof(int[]),“p3”);
ParameterExpression para4=表达式参数(typeof(数组),“p4”);
类型pt1=para3.Type.GetElementType();
类型pt2=para4.Type.GetElementType();
MethodInfo mArrayLength=Strong.Instance.Property(a=>a.Length.getMethod();
表达式asdf5=表达式.ArrayLength(para3);
表达式asdf6=表达式.ArrayLength(para4);
表达式asdf7=Expression.Call(para4,mArrayLength);
mArrayLength只是类型数组上Length属性的get方法

这里的表达式asdf5可以工作,因为para5是int[]类型,但是asdf6不能工作,因为para6的类型只是数组类型。asdf7确实有效

我想要的是有效地使用ldlen指令,它只需要一个对象,而不是调用一个方法。这只是表达式树库的一个限制吗

您可以使用反射编辑字段,甚至可以编译表达式!但是尝试运行委托将导致操作可能会破坏运行时异常的稳定性

Array parr = new int[5];

Expression pArraylength = Expression.ArrayLength(para3);
pOperandFieldInfo.SetValue(pArraylength, para4);

Expression<Func<Array, int>> pexchanger = (Expression<Func<Array, int>>)Expression.Lambda(pArraylength, para4);
Func<Array, int> pFunc = pexchanger.Compile();
int pint = pFunc(parr);
Array parr=newint[5];
表达式pArraylength=表达式ArrayLength(para3);
pOperandFieldInfo.SetValue(pArraylength,para4);
表达式pexchanger=(表达式)表达式.Lambda(pArraylength,para4);
Func pFunc=pexchanger.Compile();
int pint=pFunc(帕尔);

在.NET中有两种类型的数组,一种是由IL语言(以及
表达式
类)直接支持的一维零基(第一个索引为0)数组(
int[]
),另一种数组(多维数组,例如
int[5,3]
和第一个索引与支持它们的某些语言(例如旧VB)的兼容性不同的数组,这些语言在IL语言中没有直接支持,但由使用调用
数组的编译器支持。它们基于两个不同的类,这两个类都是
Array
的子类。正如我所写的,低级IL指令只适用于一维零基指令。
数组
对象可以是两者,因此不支持
表达式.ArrayLength

您可以很容易地在以下内容中看到这一点:

像这样使用它:

int length = compiled(new int[100]);
这里的“诀窍”是通过
FieldOffest
我们可以强制转换具有相同内存布局的不兼容类型。所有sz数组共享相同的头格式(其中包含
长度
),因此我们将
数组
转换为
字节[]
数组(请注意,我们可能已经将其转换为任何其他类型,但是
字节
有一个明显的优势:它是最小的可用类型,因此我们可以确定,我们不能以任何方式“退出”数组)

表达式树类似于:

static int GetLength(Array array)
{
    return new Conv { Array = array }.Array2.Length;
}

NET中有两种类型的数组,一种是直接受IL语言(以及
表达式
类)支持的一维零基(第一个索引为0)数组(
int[]
),另一种是其他数组(多维数组,例如
int[5,3]
和第一个索引与现有索引不同的数组,以便与支持它们的某些语言(例如旧VB)兼容),在IL语言中没有直接的支持,但编译器使用对
数组
类的调用来支持。它们基于两个不同的类,这两个类都是
数组
的子类。正如我所写的,低级IL指令只适用于一维零基指令。
数组
object可以是两者,因此不支持
Expression.ArrayLength

您可以很容易地在以下内容中看到这一点:

像这样使用它:

int length = compiled(new int[100]);
这里的“诀窍”是通过
FieldOffest
我们可以强制转换具有相同内存布局的不兼容类型。所有sz数组共享相同的头格式(其中包含
长度
),因此我们将
数组
转换为
字节[]
数组(请注意,我们可能已经将其转换为任何其他类型,但是
字节
有一个明显的优势:它是最小的可用类型,因此我们可以确定,我们不能以任何方式“退出”数组)

表达式树类似于:

static int GetLength(Array array)
{
    return new Conv { Array = array }.Array2.Length;
}

有趣的是,从cil的角度来看,只有一种对象类型(以及int32、int64、F、用户定义的值类型和本机Int).Ldlen只接受CIL中的一个对象,不是吗?我想编译一个表达式是不安全的。Arraylength当操作数的静态类型为Array时。@Nick对msdn的描述非常清楚:将基于零的一维数组的元素数推到计算堆栈上。如果在其他类型的数组上使用,则ain未定义。如果传递一个实际上是sz数组的
数组
对象,那么它将起作用(因为在
数组
t[]
之间进行转换不会更改引用),但如果实际上
数组
是一个“特殊的”数组,则会发生不好的事情。但不清楚/未定义到底会发生什么。谢谢你的帮助。规范说你可以在对象类型上运行ldlen,但正确的CIL意味着操作数必须是一维数组或null。@尼克,事实上,ldlen甚至可以用于多维数组,返回x*y大小,但很有趣从cil的角度来看,只有一个对象类型(以及int32、int64、F、用户定义值类型和本机Int)。Ldlen只接受cil中的一个对象,不是吗?我想它应该是unsa
static int GetLength(Array array)
{
    return new Conv { Array = array }.Array2.Length;
}