Now at my work I face an interesting problem: I should provide a solution with a mechanism of generating functions dynamically and to transfer it to some another algorythm. The scheme of the solution isn't clear enough by now, so I don't know how I will create these functions, but here I'd lie to talk about function transfer.

Here is a robust scheme of the problem:

x = incoming data (space X)

y = transformed data (space Y)

[Block] A -----> creation of function F: x -> y

[Block] B -----> applying F: F(x) = y

The decision to break solution into these two blocks comes from the fact that creation of F can involve great amount of data and CPU time. On the contrary, block B should work as fast as possible using current function F for transformation. Actually, block A and block B can even work on different servers. So function F should be serialized somehow and transfered to the block B.

Creation of F involves creation of some value in parameter space and it acts using some parameter p, which is created based on some stored amount of data {x}, so, actually, there exist some function W: {x} -> p (from space P) and F: x, p -> y. The question is whether block B should know about the parameter space or not (In my opinion it shouldn't cause of black box principle).

To be exact I'll describe an example for what I'm trying to do:

x = 1,2,3.....

y = 0,1

The algorythm stores some 10 values of x and then it creates a parameter space, which consist from only one value p=2 (W: {1,2,.....10} -> p=2). Then function F is created in such a way: F x, p -> y = x mod p. If block B doesn't know about the parameter space then F is transformed into F': x -> y = x mod 2 and then trasfered to block B. If it knows about parameter space then one can leave F as it is and transfer it without transformation + transfer value p = 2.

The second question is how to implement this architecture in C# (as it is primary language solution uses). Concerning delegate serialization one of the features of .NET is that Func<...> delegate is serializable, but it is so only if Func doesn't use variables from outer scope. For example:

private void FuncTest()

{

// will serialize OK with binary formatter

Func<object, object, int> func = (o1, o2) => o1.GetHashCode() | o2.GetHashCode();

// fails to serialize

int i = 10;

Func<object, object, int> func2 = (o1, o2) => (o1.GetHashCode() | o2.GetHashCode()) + i;

}

Assuming block B knows about the space P, one can consider the following solution: in block A you just accurately create a Func<P,X,Y> or some wrapper around it, insisting that P is serializable. Then one can serialize this function and some p from the space P and then create Func<X,Y> which always uses deserialized value p and deserialized Func<P,X,Y>.

This is what is needed here, but the situation can be more complicated if there are many spaces of P. That's the reason (besides some considerations of beauty and black box) I don't want block B to know about some inner spaces for block A.

If one assumes that P is hidden in the block A then situation becomes more sophisticated. The way to move on is, in my opinion, Expressions and ExpressionVisitors from System.Linq namespace. Actually, I've never used them and even didn't know about them until now. But (Linq impresses!) they seem to be powerful and flexible instruments. The way I'm currently thinking at is to make an expression (note that lambda syntax for Expressions is not equal to that for Delegates, so some conversion from Func to Expression might be needed, I was rather surprised by this) and then (when serializing) to replace all expressions in it with current values of parameters if the expression doesn't use exact parameters for the Func<X,Y>.

The task that seemed an easy thing initially is not finished yet.

Here is a robust scheme of the problem:

x = incoming data (space X)

y = transformed data (space Y)

[Block] A -----> creation of function F: x -> y

[Block] B -----> applying F: F(x) = y

The decision to break solution into these two blocks comes from the fact that creation of F can involve great amount of data and CPU time. On the contrary, block B should work as fast as possible using current function F for transformation. Actually, block A and block B can even work on different servers. So function F should be serialized somehow and transfered to the block B.

Creation of F involves creation of some value in parameter space and it acts using some parameter p, which is created based on some stored amount of data {x}, so, actually, there exist some function W: {x} -> p (from space P) and F: x, p -> y. The question is whether block B should know about the parameter space or not (In my opinion it shouldn't cause of black box principle).

To be exact I'll describe an example for what I'm trying to do:

x = 1,2,3.....

y = 0,1

The algorythm stores some 10 values of x and then it creates a parameter space, which consist from only one value p=2 (W: {1,2,.....10} -> p=2). Then function F is created in such a way: F x, p -> y = x mod p. If block B doesn't know about the parameter space then F is transformed into F': x -> y = x mod 2 and then trasfered to block B. If it knows about parameter space then one can leave F as it is and transfer it without transformation + transfer value p = 2.

The second question is how to implement this architecture in C# (as it is primary language solution uses). Concerning delegate serialization one of the features of .NET is that Func<...> delegate is serializable, but it is so only if Func doesn't use variables from outer scope. For example:

private void FuncTest()

{

// will serialize OK with binary formatter

Func<object, object, int> func = (o1, o2) => o1.GetHashCode() | o2.GetHashCode();

// fails to serialize

int i = 10;

Func<object, object, int> func2 = (o1, o2) => (o1.GetHashCode() | o2.GetHashCode()) + i;

}

Assuming block B knows about the space P, one can consider the following solution: in block A you just accurately create a Func<P,X,Y> or some wrapper around it, insisting that P is serializable. Then one can serialize this function and some p from the space P and then create Func<X,Y> which always uses deserialized value p and deserialized Func<P,X,Y>.

This is what is needed here, but the situation can be more complicated if there are many spaces of P. That's the reason (besides some considerations of beauty and black box) I don't want block B to know about some inner spaces for block A.

If one assumes that P is hidden in the block A then situation becomes more sophisticated. The way to move on is, in my opinion, Expressions and ExpressionVisitors from System.Linq namespace. Actually, I've never used them and even didn't know about them until now. But (Linq impresses!) they seem to be powerful and flexible instruments. The way I'm currently thinking at is to make an expression (note that lambda syntax for Expressions is not equal to that for Delegates, so some conversion from Func to Expression might be needed, I was rather surprised by this) and then (when serializing) to replace all expressions in it with current values of parameters if the expression doesn't use exact parameters for the Func<X,Y>.

The task that seemed an easy thing initially is not finished yet.

## Комментариев нет:

## Отправить комментарий