Maintaining a reference inside a Task? - c#

I've put together a simple demo class that looks like this:
public class HelloWorld
{
public string Name { get; set; }
}
public Main()
{
var h = new HelloWorld() { Name = "A" };
Task.Factory.StartNew(() => { Console.WriteLine(h.Name); });
h = new HelloWorld() { Name = "B" };
}
The following code prints:
B
Which is perfectly logical, but not what I want (I want to print A).
I would expect to be able to call StartNew() with an argument, which would preserve the first reference to h inside the delegate, but I can't see this option.
Am I missing something?
Edit: I can see that I can use
Task.Factory.StartNew(new Action<object>((obj) => { Console.WriteLine((obj as Hello).Name); }),h);
Being forced to pass in a type of object seems a bit .NET 1.1 / pre-generics to me though, so hoping for a better option.

What you've encountered is called a closure and it's not unique to tasks. Every time you use a variable in a lambda, it gets captured by the compiler in a special class it builds just for this purpose. The compiler generates roughly something like:
public void Main()
{
var closure = new Main_Closure();
closure.h = new HelloWorld() { Name = "A" };
Task.Factory.StartNew(closure.M1);
closure.h = new HelloWorld() { Name = "B" };
}
class Main_Closure
{
public HelloWorld h;
public void M1()
{
Console.WriteLine(h.Name);
}
}
And since closure.h could be assigned again before the task starts, you get the result you're seeing.
In this case, you can simply use another variable to store your new object. Or use another variable just before invoking the lambda, e.g.
var h1 = h;
Task.Factory.StartNew(() => { Console.WriteLine(h1.Name); });

Wrap task creation in a method to prevent closure.
static Task DoAsync<T>(Action<T> action, T arg)
{
return Task.Run(() => action(arg));
}
static void Main(string[] args)
{
Action<HelloWorld> hello = (HelloWorld h2) => { Console.WriteLine(h2.Name); };
var h = new HelloWorld() { Name = "A" };
Task task = DoAsync(hello, h);
var h = new HelloWorld() { Name = "B" };
}

What you are experiencing is a very powerful mechanism called a closure. Its extremely useful in a miriad of circumstances. Take a more in depth on how closures work at: http://csharpindepth.com/Articles/Chapter5/Closures.aspx
The problem in your case is that h changes before the Task had a chance to run. Notice that this is mere luck, some time the task might run first some others it might not.
One thing you could possibly do in your case to fix this is to simply await the Task.
If your code is on a main method you can achieve this by simply adding .Wait() at the end of your line:
var h = new HelloWorld() { Name = "A" };
Task.Factory.StartNew(() => { Console.WriteLine(h.Name); }).Wait();
h = new HelloWorld() { Name = "B" };
If you are on any other method you can simply await the task with the await keyword and making the method async:
public async Task MyMethod()
{
var h = new HelloWorld() { Name = "A" };
await Task.Factory.StartNew(() => { Console.WriteLine(h.Name); });
h = new HelloWorld() { Name = "B" };
}
Also bear in mind that using Task.Factory.StartNew is not the best option in most circumstances. Try to favour the use of Task.Run instead.

Related

Using reflection to get rid of the first two parameters in the function?

I have the following code. Is it possible to use reflection to get rid of the first two parameters since the information can be found in the Action assign (Or Expression), which will always have the form of b.P... = a.P...?
class A { .... }; var a = new A { P1 = .... } // class A and B are totally different clas
class B { .... }; var b = new B { P1 = .... } // But they have some properties with the same names
....
AssignAndDoSth(a.P1, b.P1, () => b.P1 = a.P1);
private void AssignAndDoSth<T>(T curr, T prev, Action assign) // assign can be Expression
{
if (!EqualityComparer<T>.Default.Equals(curr, prev))
{
assign();
Do(prev);
....
}
}
The short answer would be "I strongly advise against it"; in reality, this is actually an instance method of a compiler-generated capture class; so you would need to deconstruct the IL of the target method, and evaluate that IL against the fields of the target instance. Not good. What that actually looks like is something like:
var ctx = new SomeType();
ctx.a = new A { P1 = .... };
ctx.b = new B { P1 = .... };
AssignAndDoSth(a.P1, b.P1, new Action(ctx.SomeMethod));
...
class SomeType {
public A a;
public B b;
public void SomeMethod()
{
b.P1 = a.P1;
}
}
The other approach would be to refactor to an Expression<Action> - but that doesn't change the work involved much - it just presents a more friendly API (relatively speaking).
Either way, all that inspection will have a non-trivial performance cost.
An expression tree may not contain an assignment operator, but can contain operator ==
static void AssignAndDoSomething<T>(T curr, T prev, Expression<Func<bool>> assign)
{
var logExpr = assign.Body as System.Linq.Expressions.BinaryExpression;
//output rid of the first parameter
Console.WriteLine(logExpr.Left);
//output rid of the second parameter
Console.WriteLine(logExpr.Right);
//assign first parameter
Expression.Lambda<Action>(Expression.Assign(logExpr.Left, Expression.Constant(curr))).Compile()();
//assign second parameter
Expression.Lambda<Action>(Expression.Assign(logExpr.Right, Expression.Constant(prev))).Compile()();
}
class A
{
public int P1;
}
class B
{
public int P1;
}
var a = new A();
var b = new B();
AssignAndDoSomething(a.P1, b.P1, () => b.P1 == a.P1);

Calling a method twice with different values Unit testing using MOQ

I want to test a construct which calls a method within it twice to get two different values
public class stubhandler
{
public stubhandler()
{
string codetext = model.getValueByCode(int a,string b); // 1,"High" result Canada
string datatext = model.getValueByCode(int a,string b); // 10, "Slow" result Motion
}
}
To test the above i use a unit test class
[TestMethod]
public void StubHandlerConstructor_Test()
{
Mock<Model> objMock = new Mock<>(Model);
objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Canada");
objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Motion");
stubhandler classstubhandler = new stubhandler();
}
The above method pass but codetext and datatext contains same value Motion
i want them to set to
codetext = Canada
datatext = Motion
How can i achieve this?
I have tried objMock.VerifyAll() which fails the test ??
If using MOQ 4 one can use SetupSequence, else it can be done using a lambda
Using SetupSequence is pretty self explanatory.
Using the lambdas is not too messy. The important point to not it that the return value is set at the time that the setup is declared. If one just used
mockFoo.Setup(mk => mk.Bar()).Returns(pieces[pieceIdx++]);
the setup would always return pieces[0]. By using the lambda, the evaluation is deferred until Bar() is invoked.
public interface IFoo {
string Bar();
}
public class Snafu {
private IFoo _foo;
public Snafu(IFoo foo) {
_foo = foo;
}
public string GetGreeting() {
return string.Format("{0} {1}",
_foo.Bar(),
_foo.Bar());
}
}
[TestMethod]
public void UsingSequences() {
var mockFoo = new Mock<IFoo>();
mockFoo.SetupSequence(mk => mk.Bar()).Returns("Hello").Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetGreeting());
}
[TestMethod]
public void NotUsingSequences() {
var pieces = new[] {
"Hello",
"World"
};
var pieceIdx = 0;
var mockFoo = new Mock<IFoo>();
mockFoo.Setup(mk => mk.Bar()).Returns(()=>pieces[pieceIdx++]);
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetGreeting());
}
Moq documentation says you can simulate something like successive returns with Callback method:
var values = new [] { "Canada", "Motion" };
int callNumber = 0;
mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
.Returns((i,s) => values[callNumber])
.Callback(() => callNumber++);
This will do the trick, but it's not the most elegant solution. Matt Hamilton proposes much better one in his blog post, with clever use of queue:
var values = new Queue<string> { "Canada", "Motion" };
mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
.Returns(() => values.Dequeue());
Calling mock.Object.getValueByCode twice, will produce "Canada" and "Motion" strings respectively.

C# Using Assignment Lists which Reference the Assigned Variable

Does anyone know a trick that would allow me to do something like this (where Function is a Func<bool>:
UnaryNode<bool> compliment = new UnaryNode<bool>()
{ Function = () => !compliment.Right.Value };
The following works in place, but is not as nice.
UnaryNode<bool> compliment = new UnaryNode<bool>();
compliment.Function = () => !compliment.Right.Value;
This is not allowed, as documented in the langauge specification. Section 7.6.10.2:
It is not possible for the object initializer to refer to the newly
created object it is initializing.
Nor do I find your second version in any way not "nice." As for a "trick," it would be something even more "ugly." You would need to create a temporary throwaway, and then rely upon lambdas closing over the variable instead of the value. For example, given:
class Foo
{
public Func<bool> Function;
public Bar Bar;
}
class Bar
{
public bool Value;
}
You could then have
// DO NOT try this at home
Foo foo = null;
Foo temp = new Foo { Function = () => !foo.Bar.Value };
foo = temp;
bool result1 = foo.Function(); // true
foo.Bar.Value = true;
bool result2 = foo.Function(); // false
Is that more or less "nice" than what you already have?
Perhaps you can create a new class.
class ComplimentUnaryNode : UnaryNode<bool>
{
public ComplimentUnaryNode()
{
Function = () => !Right.Value;
}
}

Threading Parallel Invoke, Action

My code as below
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
for (int i = 0; i < Concurent_Downloads; i++)
{
methordList[i] = Methord;
}
Parallel.Invoke(methordList);
}
Parallel.Invoke is giving error:
"cannot convert from 'System.Action<string>[]' to 'System.Action[]'"
The Method it is calling is
public void DownloadLinks(string Term)
{
}
check Parallel.ForEach like the following
static void Main(string[] args)
{
List<string> p = new List<string>() { "Test", "Test2", "Test3"};
Parallel.ForEach(p, Test);
}
public static void Test(string test)
{
Debug.WriteLine(test);
}
This should do the trick for you
HTH
Dominik
In your case it is easier if you use
Parallel.ForEach
over your string list instead of using
Parallel.Invoke
with additional parameter. Let me know if you want to stick to Parallel.Invoke.
Parallel.Invoke accepts Action array while your code is passing it an Action<string> array. What you can do is :
public void DownloadConcurrent(Action<string> Methord)
{
Action<string>[] methordList = new Action<string>[Concurent_Downloads];
var r = methordList.Select(a => (Action)(() => a("some_str"))).ToArray();
Parallel.Invoke(r);
}
You need to replace some_str with proper value for each action

Implement VB With statement in C#

How would you create an extension method which enables me to do the following (warning: exteme pseudo-code)...
class FooBar
{
Int32 Foo { get; set; }
String Bar { get; set; }
}
new FooBar().With(fb => new Func<FooBar, Object>(instance =>
{
// VB With magic
// NOTE: The instance parameter HAS to be by reference
instance.Foo = 10;
instance.Bar;
return new Object();
}));
If you could specify anonymous functions without a return type (void), the above would look much cleaner...
new FooBar().With(fb => new Func<FooBar, void>(instance =>
{
instance.Foo = 10;
instance.Bar;
}));
This is pseudo-code of the worst kind. But I hope you get the idea.
To specify anonymous methods without return type, use Action<T> instead of Func<T, TResult>:
new FooBar().With(new Action<FooBar>(instance =>
{
instance.Foo = 10;
instance.Bar;
}));
(I don't quite see the point in this particular case, but I take your word on the pseudo code part...)
Update
Full example for being complete:
The extension method:
public static void With<T>(this T input, Action<T> action)
{
action(input);
}
Sample usage
new FooBar().With(fb =>
{
fb.Foo = 10;
fb.Bar = "some string";
});
Note that you don't need to explicitly declare the Action<FooBar>, the compiler figures that out. Should you wish to, for clarity, the call would look like this:
new FooBar().With<FooBar>(new Action<FooBar>(fb =>
{
fb.Foo = 10;
fb.Bar = "some string";
}));
Maybe this will help:
new FooBar().With( fb=> {
fb.Foo = 10;
fb.Bar = fb.Foo.ToString();
} );
// ... somewhere else ...
public static void With<T>( this T target, Action<T> action ) {
action( target );
}
As you asked how to write the extension, here goes
public static void With<T>(this T target, Action<T> action) where T : class
{
action(target);
}
Personally dont see what benefit this has, but fill yer boots!
How about just
return new FooBar{ Foo=10; };

Categories