如何在复杂数据类型上创建表达式树
我必须承认,我对 C# 中的表达式树完全陌生,但目前有必要习惯它。我的问题是我有两个包含数组的数据类型。因此,我创建了一个名为 IArray<> 的接口。
/// <summary>
/// Interface for all classes that provide a list of IArrayData
/// </summary>
public interface IArray<ElementDataType>
where ElementDataType : struct
{
/// <summary>
/// Returns a single data out fo the array container.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
IArrayData<ElementDataType> GetElementData(int index);
/// <summary>
/// Returns the amount of ArrayData.
/// </summary>
int Count
{
get;
}
/// <summary>
/// Returns the size of a single dataset in number of elements
/// (not in bytes!).
/// </summary>
/// <returns></returns>
int GetDataSize();
/// <summary>
/// Creates a copy of the array data provider, by copying the metainformation, but not the
/// contents.
/// </summary>
/// <returns></returns>
IArray<ElementDataType> CloneStub();
}
IArrayData 定义如下:
/// <summary>
/// DataProvider that provides the internal data as an array.
/// </summary>
/// <typeparam name="NativeDataType"></typeparam>
public interface IArrayData<NativeDataType> where NativeDataType : struct
{
/// <summary>
/// Returns the data in an arbitrary format.
/// The implementor must take care of an appropriate cast.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] GetData<T>() where T : struct;
/// <summary>
/// Returns the data as float[].
/// </summary>
/// <returns></returns>
float[] GetData();
/// <summary>
/// Sets the data in an arbitrary format.
/// The implementor must take care of an appropriate cast.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data_in"></param>
void SetData<T>(T[] data_in) where T : struct;
/// <summary>
/// Sets the data as float[].
/// </summary>
/// <param name="data_in"></param>
void SetData(float[] data_in);
}
有两种类型实现该接口。对于大多数数据,我必须对数据执行数学运算。目前我已经创建了自己的表达式评估器,但我很想使用表达式树,因为在我看来它更灵活。我如何在给定的接口上实现像+、-这样的数学运算?
我拥有的一种类型是我所说的 VoxelVolume,它用于存储 3D 图像数据块。 VoxelVolume 实现 IArray:
public abstract class VoxelVolume : IArray<float>
{
}
假设我有 3 个 VoxelVolume A、B 和 C。现在我想执行一个操作:
VoxelVolume D = (A + B) * C;
目前我正在使用运算符重载来执行此操作,并且效果很好。唯一的问题是,表达式是逐个操作求值的,表达式越长,花费的时间和内存就越多。我更愿意将操作合并为一个步骤。这就是我当前的实现所做的
public static IArray<float> AddMul(IArray<float> A, IArray<float> B, IArray<float> C)
{
IArray<float> Result = A.CloneStub();
int L = A.Count;
int N = A.GetDataSize();
for (int l = 0; l < L; l++)
{
float[] a = A.GetElementData(l).GetData();
float[] b = B.GetElementData(l).GetData();
float[] c = C.GetElementData(l).GetData();
float[] d = new float[a.Length];
for (int n = 0; n < N; n++)
{
d[n] = (a[n] + b[n]) * c[n];
}
Result.GetElementData(l).SetData(d);
}
return Result;
}
,但正如您可能认识到的那样,我必须为所有不同的操作输入很多内容 +、-、*、/ 等等。出于这个原因,我希望有一种更通用和灵活的方法来执行此操作。
谢谢 马丁
I must admit that I'm absolutely new to Expression Trees in C#, but currently there is a necessity to get used to it. My problem is that I have two DataTypes that contain an array of arrays. For that reason I created an interface which is called IArray<>
/// <summary>
/// Interface for all classes that provide a list of IArrayData
/// </summary>
public interface IArray<ElementDataType>
where ElementDataType : struct
{
/// <summary>
/// Returns a single data out fo the array container.
/// </summary>
/// <param name="index"></param>
/// <returns></returns>
IArrayData<ElementDataType> GetElementData(int index);
/// <summary>
/// Returns the amount of ArrayData.
/// </summary>
int Count
{
get;
}
/// <summary>
/// Returns the size of a single dataset in number of elements
/// (not in bytes!).
/// </summary>
/// <returns></returns>
int GetDataSize();
/// <summary>
/// Creates a copy of the array data provider, by copying the metainformation, but not the
/// contents.
/// </summary>
/// <returns></returns>
IArray<ElementDataType> CloneStub();
}
IArrayData is defined as following:
/// <summary>
/// DataProvider that provides the internal data as an array.
/// </summary>
/// <typeparam name="NativeDataType"></typeparam>
public interface IArrayData<NativeDataType> where NativeDataType : struct
{
/// <summary>
/// Returns the data in an arbitrary format.
/// The implementor must take care of an appropriate cast.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
T[] GetData<T>() where T : struct;
/// <summary>
/// Returns the data as float[].
/// </summary>
/// <returns></returns>
float[] GetData();
/// <summary>
/// Sets the data in an arbitrary format.
/// The implementor must take care of an appropriate cast.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="data_in"></param>
void SetData<T>(T[] data_in) where T : struct;
/// <summary>
/// Sets the data as float[].
/// </summary>
/// <param name="data_in"></param>
void SetData(float[] data_in);
}
There are two types that implement the interface. On most of the data I have to perform mathematical operations on the data. Currently I have created my own expression evaluator, but I would love to use the expression trees because it seems to me that it's more flexible. How would I implement a mathematical operation like +, - on the given interface?
One type I have is what I call VoxelVolume, which is to store a 3d block of image data. VoxelVolume implements IArray:
public abstract class VoxelVolume : IArray<float>
{
}
Lets assume I have 3 VoxelVolumes A, B, and C. Now I want to perform an operation:
VoxelVolume D = (A + B) * C;
Currently I'm doing this with operator overloading and it works quite well. The only problem is, that the expression is evaluated operation by operation and the longer the expression is the more time and memory it takes. I would prefer to combine the operation in one single step. This is what my current implementation does
public static IArray<float> AddMul(IArray<float> A, IArray<float> B, IArray<float> C)
{
IArray<float> Result = A.CloneStub();
int L = A.Count;
int N = A.GetDataSize();
for (int l = 0; l < L; l++)
{
float[] a = A.GetElementData(l).GetData();
float[] b = B.GetElementData(l).GetData();
float[] c = C.GetElementData(l).GetData();
float[] d = new float[a.Length];
for (int n = 0; n < N; n++)
{
d[n] = (a[n] + b[n]) * c[n];
}
Result.GetElementData(l).SetData(d);
}
return Result;
}
But as you may recognize I have to type a lot for all different operations +,-,*,/ and a lot more. For that reasons I'd like to have a more generic and flexible way to perform this operations.
Thanks
Martin
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
在您的示例中,我假设在标准代码中运行
GetData()
调用是合理的,尽管由于我们可能不知道“深度”,所以我们可以简化为锯齿状数组(矩形阵列也可以工作,但在所有方面都更难使用,所以我们不要这样做)。因此,假设我们有一个锯齿状数组,而不是a
、b
、c
(尽管我们假设答案为d
> 很简单)。因此,我们实际上需要构建:即作为一棵树:
因此我们可以构建一个表达式(并评估),通过:
显然,您的实际代码需要解析您的输入表达式并构建一个类似的树灵活地;但这应该足以说明一般方法。
In your example, I'm assuming that it would be reasonable to run the
GetData()
calls in your standard code, although since we might not know the "depth", we can simplify to a jagged array (a rectangular array would work too, but is harder to work with at all points, so let's not do that). So imagine we have a jagged array instead ofa
,b
,c
(although we'll assume the answersd
is simple enough). Thus, we actually need to build:which is, as a tree:
So we can build an expression (and evaluate), via:
Obviously your actual code needs to parse your input expression and build a similar tree flexibly; but this should be enough to illustrate a general approach.