I've got a function,
public SharpQuery Each(Action<int, HtmlNode> function)
{
for (int i = 0; i < _context.Count; ++i)
function(i, _context[i]);
return this;
}
Which calls the passed in function for each element of the context. Is it possible to set what "this" refers to inside Action<int, HtmlNode> function?
For example,
sharpQuery.Each((i, node) => /* `this` refers to an HtmlNode here */);
With a slight change in the function, you can achieve the desired effect.
public SharpQuery Each(Action<MyObject, int, HtmlNode> function)
{
for (int i = 0; i < _context.Count; ++i)
function(this, i, _context[i]);
return this;
}
Then you could write your function call like so:
sharpQuery.Each((self, i, node) => /* do something with `self` which is "this" */);
Note: The anonymous function will only have access to public members however. If the anonymous function was defined within the class, it will have access to protected and private members as usual.
e.g.,
class MyObject
{
public MyObject(int i)
{
this.Number = i;
}
public int Number { get; private set; }
private int NumberPlus { get { return Number + 1; } }
public void DoAction(Action<MyObject> action)
{
action(this);
}
public void PrintNumberPlus()
{
DoAction(self => Console.WriteLine(self.NumberPlus)); // has access to private `NumberPlus`
}
}
MyObject obj = new MyObject(20);
obj.DoAction(self => Console.WriteLine(self.Number)); // ok
obj.PrintNumberPlus(); // ok
obj.DoAction(self => Console.WriteLine(self.NumberPlus)); // error
No.
Well, yes, if the Action was created in such a scope where 'this' was available and bound in a closure -- but transparently: no.
Pass in all needed information or make sure it's captured/available in the Action itself. There are other hacks like thread-locals, etc. Best avoided.
Related
My code:
public class BaseParamsClass
{
public BaseParamsClass(int pBaseParam = 0)
{
baseParam = pBaseParam;
}
public int baseParam;
}
public class Parent1ParamsClass : BaseParamsClass
{
public Parent1ParamsClass(int pBaseParam = 0) : base(pBaseParam)
{
}
public int parentParam1;
}
public class Parent2ParamsClass : BaseParamsClass
{
public Parent2ParamsClass(int pBaseParam = 0) : base(pBaseParam)
{
}
public int parentParam2;
}
public delegate void Parent1Callback(Parent1ParamsClass theParams);
public delegate void Parent2Callback(Parent2ParamsClass theParams);
private IEnumerator CoRFunction1(Parent1Callback parent1Callback)
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
parent1Callback(new Parent1ParamsClass(0));
}
private IEnumerator CoRFunction2(Parent2Callback parent2Callback)
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
// Need a generic way to do the next line:
parent2Callback(new Parent2ParamsClass(0));
}
private IEnumerator CoRFunction2(Parent2Callback parent2Callback)
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
// Need a generic way to do the next line:
parent2Callback(new Parent2ParamsClass(0));
}
And what i need is a way to replace the line after the '// Need a...' in something more generic, this is how the last two functions should look like:
private IEnumerator CoRFunction1(Parent1Callback parent1Callback)
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
genericFunction<Parent1Callback>(Parent1ParamsClass);
}
private IEnumerator CoRFunction2(Parent2Callback parent2Callback)
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
genericFunction<Parent2Callback>(Parent2ParamsClass);
}
Any ideas how to create 'genericFunction'?
I commented - it's not too clear exactly what you're trying to achieve and I suspect you can do this in a better way than what you are trying to... but for the record, I think something like the below might work.
Change the base parameter classes so you're not relying on the constructor to set their internal fields, then constrain some generic methods to the base type only, so you'd end up with this sort of thing:
public class BaseParamsClass
{
public virtual void SetParam(int pBaseParam)
{
baseParam = 0;
}
public int baseParam;
}
public class Parent1ParamsClass : BaseParamsClass
{
public override void SetParam(int pBaseParam)
{
base.SetParam(pBaseParam);
//do other stuff specific to this class...
}
public int parentParam1;
}
public class Parent2ParamsClass : BaseParamsClass
{
public override void SetParam(int pBaseParam)
{
base.SetParam(pBaseParam);
//do other stuff specific to this class...
}
public int parentParam2;
}
public delegate void GenericCallback<T>(T theParams) where T : BaseParamsClass, new();
private IEnumerator GenericCorFunction<T>(GenericCallback<T> callback) where T:BaseParamsClass, new()
{
// This demonstrate few actions i do before the call
yield return new WaitForSeconds(1);
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
//I assume you want result here.
//Also note that you can't use the constructor to set the base param as at compile time
//we're not sure which type will be being used. There are ways around this but it's
//probably clearer to use basic constructor then call the SetParam virtual/overridden method
var param = new T();
param.SetParam(result);
callback(param);
}
you could use it something like this:
var newEnumerator = GenericCorFunction<Parent2ParamsClass>(p =>
{
//this is the callback function body. This will only run when
//called at the end of the GenericCorFunction
//Do things with p, which will be a PArent2ParamsClass object
//with its baseParam field set to whatever result was.
if (p.baseParam == 3)
{
throw new NotImplementedException();
}
});
//do stuff with newEnumerator...
Another approach could be to use Activator.CreateInstance. This will allow you to circumvent the new() restriction and to use your already written constructor:
public delegate void ParentCallback<T>(T theParams) where T : BaseParamsClass;
private void CoRFunction<T>(ParentCallback<T> parentCallback) where T : BaseParamsClass
{
// Now i get the result, it can be 0-10, each one should activate different callback
int result = 0;
parentCallback((T)Activator.CreateInstance(typeof(T), 11));
}
(I changed it into void to make it testable for me)
Here is the TestCode and the calls I used to test it:
public void Call_1(Parent1ParamsClass par1)
{
Console.WriteLine("CALL 1 baseParam: " + par1.baseParam);
}
public void Call_2(Parent2ParamsClass par2)
{
Console.WriteLine("CALL 2 baseParam: " + par2.baseParam);
}
Calls:
CoRFunction<Parent1ParamsClass>(Call_1);
CoRFunction<Parent2ParamsClass>(Call_2);
Output:
CALL 1 baseParam: 11
CALL 2 baseParam: 11
How I can to pass a reference as a parameter to Async method in Windows Store App ? I'm looking for something like this:
var a = DoThis(ref obj.value);
public async Task DoThis(ref int value)
{
value = 10;
}
But error:
Async methods cannot have ref or out parameters
Has any another way?
Note:I need to pass exactly obj.value. This method would be used by different types of objects, by same type of objects, by one object, but I will pass obj.val_1, obj.val_2 or obj.val_10. All values will be same type (for ex string)
If you don't care about a little overhead and possibly prolonged lifetime of your objects, you could emulate the ref behavior by passing a setter and a getter method to the function, like this:
public async Task DoStuff(Func<int> getter, Action<int> setter)
{
var value1 = getter();
await DoSomeOtherAsyncStuff();
setter(value1 * value1);
}
And call it like this:
await DoStuff(() => obj.Value, x => obj.Value = x);
You could directly pass the object itself and set the value of the corresponding property inside the method:
var a = DoThis(obj);
public async Task DoThis(SomeObject o)
{
o.value = 10;
}
And if you do not have such object simply write one and have the async method take that object as parameter:
public class SomeObject
{
public int Value { get; set; }
}
You can always use the Task<> class and return the desired value. Then Your code would look something like:
var a = DoThis(obj.value);
obj.value = a.Result;
public async Task<int> DoThis(int value)
{
int result = value + 10; //compute the resulting value
return result;
}
EDIT
Ok, the other way to go with this that I can think of is encapsulating the update of the given object's member in a method and then passing an action invoking this method as the task's argument, like so:
var a = DoThis(() => ChangeValue(ref obj.value));
public void ChangeValue(ref int val)
{
val = 10;
}
public async Task DoThis(Action act)
{
var t = new Task(act);
t.Start();
await t;
}
As far as I tested it the change was made in the child thread, but still it's effect was visible in the parent thread. Hope this helps You.
You can't do this as you have it (as you know). So, a few work arounds:
You can do this by passing the initial object since it will be a reference type
var a = DoThis(obj);
public async Task DoThis(object obj) //replace the object with the actual object type
{
obj.value = 10;
}
EDIT
Based upon your comments, create an interface and have your classes implement it (providing it's always the same type you want to pass). Then you can pass the interface which is shared (maybe over kill, depends on your needs, or even unrealistic amount of work).
Or, provide a base class with the property! (I don't like this suggestion but since you're asking for something which can't be done it may suffice although I don't recommend it).
An example of the interface is here (not using what you have, but close enough using a Colsone App)
using System;
namespace InterfacesReferenceTypes
{
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
DoThis(mc);
Console.WriteLine(mc.Number);
Console.ReadKey();
}
static void DoThis(IDemo id)
{
id.Number = 10;
}
}
class MyClass : IDemo
{
//other props and methods etc
public int Number { get; set; }
}
interface IDemo
{
int Number { get; set; }
}
}
EDIT2
After next comments, you will have to still use an interface, but re assign the value afterwards. I'm sure there is a better way to do this, but this works:
using System.Text;
namespace InterfacesRerefenceTypes
{
class Program
{
static void Main(string[] args)
{
MyClass mc = new MyClass();
Console.WriteLine(mc.Number);
mc.val1 = 3;
mc.val2 = 5;
mc.Number = mc.val2;
DoThis(mc);
mc.val2 = mc.Number;
Console.WriteLine(mc.val2);
Console.ReadKey();
}
static void DoThis(IDemo id)
{
id.Number = 15;
}
}
class MyClass : IDemo
{
public int val1 { get; set; }
public int val2 { get; set; }
public int Number { get; set; }
}
interface IDemo
{
int Number { get; set; }
}
}
Why is Visual Studio 2010 telling me "'System.Delegate' does not contain a definition for 'EndInvoke'" when I call job.Delegate.EndInvoke()? How do I fix it? Note that it likes BeginInvoke() just fine, and doesn't complain if I add EndInvoke() immediately after BeginInvoke() (thought hat doesn't accomplish what I want).
I have a little JobTracker class for tracking backup jobs:
public class JobTracker
{
private class Job
{
public Account Account { get; set; }
public IAsyncResult Result { get; set; }
public Delegate Delegate { get; set; }
public bool IsCompleted { get { return result.IsCompleted } }
public string Instance { get { return Account.Instance } }
}
public List<Job> Running = new List<Job>;
public void AddJob(Account a, IAsyncResult result, Delegate del)
{
var j = new Job { Account = a, Result = result, Delegate = del };
Running.Add(j);
}
public void RemoveJob(Job job)
{
Running.Remove(job);
}
public bool IsInstanceRunning(string instance)
{
return (Running.Count(x => x.Instance == instance) > 0);
}
}
These backup jobs will happen asynchronously via BeginInvoke()/EndInvoke(). The calling code (simplified) looks something like this:
public void BackupAccounts(IEnumerable<Account> accounts, int maxconcurrent = 4)
{
// local copy
List<Accounts> myaccounts = accounts.ToList();
var jobs = new JobTracker();
while (myaccounts.Count > 0)
{
// check our running jobs
foreach (var job in jobs.Running)
{
if (job.IsCompleted)
{
// PROBLEM LINE:
job.Delegate.EndInvoke();
jobs.RemoveJob(job);
}
}
// more jobs!
while (jobs.Count < maxconcurrent)
{
int i = 0;
Account account = null;
// choose the next account on a free instance
while (int < accounts.Count)
{
account = accounts[i];
// instance in use?
if (jobs.InstanceIsRunning(account.Instance))
{
i += 1;
continue;
}
else
{
// start the job
accounts.RemoveAt(i);
BackupDelegate del = new BackupDelegate(BackupAccount, account);
IAsyncResult result = del.BeginInvoke();
jobs.AddJob(account, result, del);
}
}
}
// we're all full up, give it some time to work
Thread.Sleep(2000);
}
}
PS - I know this code can be greatly simplified. It's a first, get-it-working iteration -- I just can't figure out why VS doesn't like it.
When you call BeginInvoke, you're calling it on a specific subclass of Delegate. When you call EndInvoke, you're trying to call it on System.Delegate itself, which won't work. Each subclass declares its own Invoke/BeginInvoke/EndInvoke set of methods - which it has to, given that the signatures of the methods varies according to the signature of the exact delegate type you're talking about. If you look at the documentation for System.Delegate you won't find any of those methods there.
It's not really clear what your code is trying to achieve, but if you want to call EndInvoke, you'll need to make Job.Delegate a specific delegate type.
Because EndInvoke doesn't exist on Delegate. Instead you should have your Job class hold a reference to a BackupDelegate.
What do I have to do to say that InvokeMethod can invoke a method and when using special options like Repeat it shall exexute after the Repeat.
My problem for now is that the method will already exexute before it knows that it has to be called 100 times.
class Program
{
static void Main()
{
const bool shouldRun = true;
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process);
}
}
MethodExpression
public class MethodExpression
{
private bool _isTrue = true;
private readonly MethodExecuter _methodExecuter;
public MethodExpression(bool isTrue, MethodExecuter methodExecuter)
{
_isTrue = isTrue;
_methodExecuter = methodExecuter;
}
public MethodExecuter ThenInvokeMethod(Action action)
{
if (_isTrue)
{
action.Invoke();
_isTrue = false;
}
return _methodExecuter;
}
}
MethodExecuter
public class MethodExecuter
{
private bool _condition;
private int _repeat = 1;
public MethodExpression When(bool isTrue)
{
return new MethodExpression(isTrue && _condition, this);
}
public MethodExecuter InvokeMethod(Action action)
{
if (_condition)
{
for (int i = 1; i <= _repeat; i++)
{
action.Invoke();
}
}
return this;
}
public MethodExecuter ForAllInvocationsUseCondition(bool condition)
{
_condition = condition;
return this;
}
public MethodExecuter Repeat(int repeat)
{
_repeat = repeat;
return this;
}
}
Use a final method ("go", or "execute") to actually kick things off.
new MethodExecuter()
.ForAllInvocationsUseCondition(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun).ThenInvokeMethod(B.Process).Repeat(10)
.ForAllInvocationsUseCondition(Context.WannaShutDown)
.When(shouldRun).ThenInvokeMethod(C.Process)
.Go();
What you've provided looks a bit like programming a workflow or state machine. In order to capture invocations and respect conditions during execution, you'd need to change your approach slightly.
Instead of invoking actions as they come in, consider pushing your actions into a queue and then providing an mechanism to run the state machine.
new MethodInvoker()
.ForAllInvocationsUseCondition(true)
.InvokeMethod( Process.A ).Repeat(100)
.Run();
There are a lot of ways to skin this cat, but I think one source of this difficulty is in the fact that you actually invoke the method within the InvokeMethod() method (go figure!).
Typically, we use fluent APIs to turn syntax that is evaluated from the inside-out into something that can be expressed in a left-to-right fashion. Thus, the expression builder components of the interface are used to build up state throughout the expression, and only at the end does the "real work" happen.
One solution to your immediate problem is to queue up each action with its associated options (invocation conditions, repeat count, etc.), and add some ExecuteAll() method to MethodExecuter that dequeues and executes the fully configured actions at the end of the member chain.
Another solution would be to put all of the execution options inside the InvokeMethod() method; something like:
.Invoke(x => x.Method(A.Process).Repeat(100))
This method would look something like:
public MethodExecuter Invoke(Action<IExecutionBuilder> executionBuilder)
{
var builder = new ExecutionBuilder();
executionBuilder(builder);
var action = builder.Action;
var repeat = builder.RepeatCount;
if (_condition)
{
for (int i = 1; i <= repeat; i++)
{
action();
}
}
return this;
}
I haven't worked through this in Visual Studio, but the other items would be something like:
public interface IExecutionBuilder
{
IExecutionBuilder Method(Action action);
IExecutionBuilder Repeat(int count);
}
public class ExecutionBuilder : IExecutionBuilder
{
public ExecutionBuilder()
{
RepeatCount = 1; // default to repeat once
Action = () => {}; // default to do nothing, but not null
}
public IExecutionBuilder Method(Action action)
{
Action = action;
return this;
}
public IExecutionBuilder Repeat(int repeat)
{
RepeatCount = repeat;
return this;
}
public int RepeatCount { get; private set; }
public Action Action { get; private set; }
}
Note that RepeatCount and Action are not exposed on the interface. This way, you will not see these members when calling .Invoke(x => x., but will have access to them when using the concrete ExecutionBuilder class inside the Invoke() method.
You could have a SetInvokeMethod and an Execute Method.
SetInvokeMethod(Action).Repeat(100).Execute()
In a sentence, your code is too "eager". The InvokeMethod method is called, and performs the action, before your fluent grammar structure tells your code how many times it should repeat.
To change this, try also specifying the method you are invoking as a private field in your methodInvoker, then include a command that is a "trigger" to actually perform the commands. The key is "lazy evaluation"; in a fluent interface, nothing should be done until it has to; that way you have most of the control over when it does happen.
public class FluentMethodInvoker
{
Predicate condition = ()=>true;
Predicate allCondition = null;
Action method = ()=> {return;};
bool iterations = 1;
FluentMethodInvoker previous = null;
public FluentMethodInvoker(){}
private FluentMethodInvoker(FluentMethodInvoker prevNode)
{ previous = prevNode; }
public FluentMethodInvoker InvokeMethod(Action action)
{
method = action;
}
//Changed "When" to "If"; the function does not wait for the condition to be true
public FluentMethodInvoker If(Predicate pred)
{
condition = pred;
return this;
}
public FluentMethodInvoker ForAllIf(Predicate pred)
{
allCondition = pred;
return this;
}
private bool CheckAllIf()
{
return allCondition == null
? previous == null
? true
: previous.CheckAllIf();
: allCondition;
}
public FluentMethodInvoker Repeat(int repetitions)
{
iterations = repetitions;
return this;
}
//Merging MethodExecuter and MethodExpression, by chaining instances of FluentMethodInvoker
public FluentMethodInvoker Then()
{
return new FluentMethodInvoker(this);
}
//Here's your trigger
public void Run()
{
//goes backward through the chain to the starting node
if(previous != null) previous.Run();
if(condition && CheckAllIf())
for(var i=0; i<repetitions; i++)
method();
return;
}
}
//usage
class Program
{
static void Main()
{
const bool shouldRun = true;
var invokerChain = new FluentMethodInvoker()
.ForAllIf(!Context.WannaShutDown)
.InvokeMethod(A.Process).Repeat(100)
.When(shouldRun)
.Then().InvokeMethod(B.Process).Repeat(10)
.ForAllIf(Context.WannaShutDown)
.When(shouldRun)
.Then().InvokeMethod(C.Process);
//to illustrate that the chain doesn't have to execute immediately when being built
invokerChain.Run();
}
}
I have a class defined with a generic:
public class GenericDataStore<T>
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
public void addData(T data) { dataQueue.Add(data); }
public T getLastData() { dataQueue.getLastData(); }
}
I then have different derived classes based on this class:
public class ByteDataStore : GenericDataStore<Byte>
{
}
public class DoubleDataStore : GenericDataStore<Double>
{
}
public class PObjDataStore : GenericDataStore<PObj> // PObj is another class declared somewhere
{
}
Then, I have a "Manager" class that looks like:
public class DataManager
{
/* Here, I want to declare a 2 dim array [,] that holds pointers to the
data stores. Depending on some other variables, the array may need
to point to DoubleDataStore, ByteDataStore, etc. The following doesn't work,
since GenericDataStore must be declared with a generic type: */
GenericDataStore [,] ManagedDataStores; // Can not compile
public DataManager() {
for (int i=0; i<numStores; i++) {
for (int j=0; j<numCopies; j++) {
// objType is a utility function that we have that returns a type
if (objType(i,j) == typeof(Byte)) {
ManagedDataStores[i,j] = new ByteDataStore();
} else if (objType(i,j) == typeof(double)) {
ManagedDataStores[i,j] = new DoubleDataStore();
}
}
}
}
void Add(int id, int copyid, Byte data) {
ManagedDataStores[i,j].Add(data);
}
}
There might be other, better ways to do this. Essentially, we want to have different data stores for different object types, which can be managed by a class. We want only this 'manager' class to be exposed to the user (like an API), and no direct access to the underlying classes.
Thanks in advance.
I'm afraid that this is one of those instances where Generic's don't help you one bit. By definition, you must know the generic type at compile time, rather than runtime. For runtime type-indiference, you need to do it the old-fashioned way.
public class DataStore
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore dataQueue = new UnderlyingDataStore();
public void addData(object data) { dataQueue.Add(data); }
public object getLastData() { dataQueue.getLastData(); }
}
This, has the obvious drawback of boxing/unboxing- as well as the need for calling-code to know what type's it should be dealing with in order to cast.
However, you could also use the other answer, as long as you're able to cast the managedDataStore to the correct generic type.
If you want to create and initialize the double dimensional array use this:
int numStores = 2;
int numCopies = 3;
//GenericDataStore<object>[,] managedDataStores = new GenericDataStore<object>[numStores,numCopies];
Object[,] managedDataStores = new Object[numStores,numCopies];
for (int i = 0; i < numStores; i++)
{
for (int j = 0; j < numCopies; j++)
{
managedDataStores[i,j] = new GenericDataStore<object>();
}
}
I would add an interface and implement it explicitly to hide it from the class users:
internal interface GeneralDataStore
{
void addData(object data);
object getLastData();
}
public class GenericDataStore<T> : GeneralDataStore
{
// UnderlyingDataStore is another class that manages a queue, or a linked list
private UnderlyingDataStore<T> dataQueue = new UnderlyingDataStore<T>();
public void addData(T data) { dataQueue.Add(data); }
public T getLastData() { dataQueue.getLastData(); }
object GeneralDataStore.getLastData() { return getLastData(); }
void GeneralDataStore.addData(object data) { add((T)data); }
}
GeneralDataStore [,] ManagedDataStores;
This doesn't give you what you want, since it's impossible. But it give you some type safety.