I am trying to call a method with arguments, but it doesn't work. I have this method:
public class AllMethods
{
//method change state and status of entity objetivovisitacao for "Propagado"
public static void changeStatus(Guid objetivoId, IOrganizationService service, int state)
{
SetStateRequest setStateRequest = new SetStateRequest
{
EntityMoniker = new EntityReference("statuscode", objetivoId),
State = new OptionSetValue(0),
Status = new OptionSetValue(911950001),
};
service.Execute(setStateRequest);
}
}
And I need to call that method, so I tried doing it this way:
AllMethods.changeStatus();
But it's wrong. Can someone explain this so that I can better understand what I'm missing here?
First create variables for the parameters of the method. Then pass them in the same order as they was declared in the method.
Guid yourObjetivoId = new Guid();
IOrganizationService yourService = New YourImplementationOfOrganizationService();
int yourState = 3;
AllMethods.changeStatus(yourObjetivoId, yourService, yourState);
From MSDN: Methods (C# Programming Guide)
The method definition specifies the names and types of any parameters
that are required.
When calling code calls the method, it provides
concrete values called arguments for each parameter.
The arguments
must be compatible with the parameter type but the argument name (if
any) used in the calling code does not have to be the same as the
parameter named defined in the method
No need to state the types of the parameters when passing them through.
You should call it like this:
AllMethods.changeStatus(objetivoId, service, state);
you need to pass the parameters, see documentation: Pass parameters c#
in your case
AllMethods.changeStatus(objetivoId, service, state);
If you declare a method like you did:
public static void changeStatus(Guid objetivoId, IOrganizationService service, int state)
you declare parameters in the parentheses. The compiler expects the necessary input when you try to call it. So you need the fitting parameters for the call of this method. It is like a key to a lock.
Guid objetivoId = // your value
IOrganizationService service = // your value
int state = // your value
then you call it like this:
AllMethods.changeStatus(objetivoId, service, state);
You don't need to declare them again in the call! it has to be done beforehand
You are doing it wrong since, you are declaring the types of the parameter here:
AllMethods.changeStatus(Guid objetivoId, IOrganizationService service, int state);
for calling this method changeStatus(...), you need to pass the variable for the parameters objetivoId, service, state.
AllMethods.changeStatus(objetivoId, service, state);
See: Passing of Parameters in C#
MSDN:
In C#, arguments can be passed to parameters either by value or by
reference.
Related
I have three projects
MVC Web application
Service application which is kind of two layers business/repository
Entity framework (all EF configuration lives here)
MVC references > service
Service references > EF
I have these three methods currently that do some work.
public bool StoreUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool RemoveUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
public bool CommitUpload<T>(UploadInformation information)
where T : class, IUploadEntity { }
I call these three methods from my controller using these interfaces which delegate to the work methods above:
Boolean StoreUpload(UploadInformation information);
Boolean RemoveUpload(UploadInformation information);
Boolean CommitStoredDocuments(UploadInformation information);
Based on a condition from UploadTypes enumeration in a switch I call the correct work method. I do this because I don't want my mvc project to have access to the EF database types otherwise I know someone is going to start querying data from all over the application. I use these switch statements for all interfaced methods:
public bool StoreUpload(UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return RemoveUpload<AutoIncident>(information);
case UploadTypes.Incident:
return RemoveUpload<IncidentInjury>(information);
case UploadTypes.Inspection:
return RemoveUpload<Inspection>(information);
case UploadTypes.OtherIncident:
return RemoveUpload<OtherIncident>(information);
default:
return false;
}
}
public bool RemoveUpload(UploadInformation information) { ... }
public bool CommitStoredUpload(UploadInformation information) { ... }
This method might shed a little light on what the types parameters are being used for. I am updating tables in a generic way using EF.
private bool CommitStoredDocuments<T>(UploadInformation information) where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
...
}
It would be nice to be able to pass the work method which requires a type parameter as a delegate to the switch work method calls.
public bool DoSomeWork(delegateMethod, information) {
switch(information.Type) {
case UploadTypes.AutoInciden:
return delegateMethod<AutoIncident>(information);
...
}
}
Can this be done?
Also, I had trouble constructing a good title for this question so please comment if these is a better way to describe the challenge.
It cannot be done directly due to several reasons.
First of all, as you probably noticed, delegateMethod<FooBar>(information) simply does not compile. This is because in your example the delegateMethod is a local variable (method parameter actually, but still a variable), and you cannot apply "type arguments" <FooBar> to a variable - you can apply them only on an identifier that indicates a (generic) type or a (generic) method.
Second reason is more interesting. When you pass a method as a delegate, the delegate actually catches the whole method signature, including all parameter types.
void Blah<T>(UploadInformation information){ ... }
var one = new Action<int>(Blah); // -> Blah<int>
var two = new Action<float>(Blah); // -> Blah<float>
var thr = new Action<andsoon>(Blah); // -> Blah<andsoon>
MagicDoSomeWork(one, ...); // these all
MagicDoSomeWork(two, ...); // delegates are already bound
MagicDoSomeWork(thr, ...); // and remember their concrete T
You need to actually specify the type for the Action so a proper version of generic method will be picked from a general description called Blah. These delegates are bound to concrete versions of the method and will accept only that types. These delegates are 'closed' in terms of their type arguments. Using normal ways, the MagicDoSomeWork will simply have no way of altering the T which these delegates already have remembered.
That two things are a kind of show stoppers, since by normal code only, you cannot write things like
var nope1 = new Action(Blah); // ctor for Action NEEDS type parameter
since Action constructor simply requires a type parameter. And once you pass any, it will lock the Blah type arguments
Also you cannot use open delegates:
var nope1 = new Action<>(Blah); // can't use empty <> in this context :(
since new operator requires a full type to create an object.
However, with a bit of reflection voodoo, it is possible to analyze and build a generic type or a generic method dynamically.
// first, build the delegate in a normal way
// and pick anything as the type parameters
// we will later replace them
var delegateWithNoType = new Action<object>(Blah);
// delegate has captured the methodinfo,
// but uses a stub type parameter - it's useless to call it
// but it REMEMBERS the method!
// .... pass the delegate around
// later, elsewhere, determine the type you want to use
Type myRealArgument;
switch(..oversomething..)
{
default: throw new NotImplemented("Ooops");
case ...: myRealArgument = typeof(UploadTypes.AutoIncident); break;
...
}
// look at the delegate definition
var minfo = delegateWithNoType.Method;
var target = delegateWithNoType.Target; // probably NULL since you cross layers
var gdef = minfo.GetGenericDefinition();
var newinfo = gdef.MakeGenericMethod( myRealArgument );
// now you have a new MethodInfo object that is bound to Blah method
// using the 'real argument' type as first generic parameter
// By using the new methodinfo and original target, you could now build
// an updated delegate object and use it instead the original "untyped" one
// That would be a NEW delegate object. You can't modify the original one.
// ...but since you want to call the method, why don't use the methodinfo
UploadInformation upinfo = ... ;
newinfo.Invoke(target, new object[] { upinfo });
// -> will call Blah<UploadTypes.AutoInciden>(upinfo)
word of warning: this is a sketch to show you how the delegate.Method/Target and methodinfo and getgenericdefinition and makegenericmethod work. I wrote it from memory, never compiled, never ran. It can contain minor typos, overlooked things and invisible rainbow unicorns. I didn't noticed any. Probably because they were invisible.
You can do it like this
public bool Invoke(EntityType entityType, ActionType action, Object[] arguments)
{
var actionType = Enum.GetName(typeof(ActionType), action);
var type = GetType();
var method = type.GetMethods().Single(m => m.IsGenericMethod && m.Name == actionType);
switch (entityType)
{
case EntityType.IncidentInjury:
var genericMethod = method.MakeGenericMethod(typeof(IncidentInjury));
return (bool)genericMethod.Invoke(this, arguments);
default:
return false;
}
}
The enum will just be a list of methods that I want to invoke this way and I create a base class for my services so I don't have to pass the instance to the Invoke method.
Instead of using delegates, consider using an interface (or abstract class). This way, your methods can retain their generic nature.
For example, if you create an interface like:
interface IUploadAction
{
bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity;
}
Note that the T is not exposed in the type, it's only on the method. This is the key part.
Now you can implement this for your database methods:
class CommitStoredDocuments : IUploadAction
{
public bool Perform<T>(UploadInformation information)
where T : class, IUploadEntity
{
var uploads = GetStoredUploads(information.UniqueId);
var entity = db.Set<T>().Include(e => e.Uploads)
.Single(e => e.UniqueId == information.UniqueId);
entity.Uploads.AddRange(uploads);
//...
}
}
Your switching/dispatching method can look like this:
public bool DoAction(IUploadAction action, UploadInformation information)
{
switch (information.Type)
{
case UploadTypes.AutoIncident:
return action.Perform<AutoIncident>(information);
case UploadTypes.Incident:
return action.Perform<IncidentInjury>(information);
case UploadTypes.Inspection:
return action.Perform<Inspection>(information);
case UploadTypes.OtherIncident:
return action.Perform<OtherIncident>(information);
default:
return false;
}
}
And then you can write something like:
IUploadAction storeUpload;
public bool StoreUpload(UploadInformation information) => DoAction(storeUpload, information);
I am using 3 tier architecture in my C# Window Form. The thing I want to do is, hide the button if the data is exists. Here are my codes.
Class File
public bool checkIfExists(Variables variables) { // BelPar
SqlCommand check = new SqlCommand();
check.Connection = dbcon.getcon();
check.CommandType = CommandType.Text;
check.CommandText = "SELECT * FROM tbl";
SqlDataReader drCheck = check.ExecuteReader();
if(drCheck.HasRows == true)
{
drCheck.Read();
if (... && .. ||) // conditions where variables are being fetch
{
return false;
}
}
drCheck.Close();
return true;
}
Window Form
btn_save.Visible = !balpayrolldetails.checkIfExists(); // This is where I get the "No overload for method 'checkIfExists' takes 0 arguments.
Any help? Please leave or answer below. Thank you
To call a method, you need to call it by its exact name, which in this case is:
checkIfExists(Variables variables);
This tells us that to use this method, we need to pass it in an object of type Variables to be used in the method execution.
Whichever types are outlined in the method signature must be provided to successfully call a method.
You will need to update your call from
btn_save.Visible = !balpayrolldetails.checkIfExists();
to
btn_save.Visible = !balpayrolldetails.checkIfExists(someVariablesOfTheExpectedType);
Having the method signature:
public bool checkIfExists(Variables variables)
It should be called by passing an object of type Variables to the method:
btn_save.Visible = !balpayrolldetails.checkIfExists(anInstanceOfVariables);
But if it's acceptable for you to call the method parameter-less and your method is written in a way that can tolerate having variables with null value, you can change the signature to this:
public bool checkIfExists(Variables variables=null)
And then you can call it this way:
btn_save.Visible = !balpayrolldetails.checkIfExists();
I'm learning socket programming and I have the following function:
public void OnDataReceived(IAsyncResult asyn)
and this is how the callback gets set:
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
The problem is I need to pass another argument to OnDataReceived callback function, how can I do this? I'm trying to make a simple tcp server and I need to track from which client the data is coming from. Any tips? Thanks!
I'm going to presume you're using System.Net.Sockets.Socket here. If you look at the overloads of BeginReceive you'll see the object parameter (named state). You can pass an arbitrary value as this parameter and it will flow through to your AsyncCallback call back. You can then acess it using the AsyncState property of IAsyncResult object passed into your callback. Eg;
public void SomeMethod() {
int myImportantVariable = 5;
System.Net.Sockets.Socket s;
s.BeginReceive(buffer, offset, size, SocketFlags.None, new new AsyncCallback(OnDataReceived), myImportantVariable);
}
private void OnDataReceived(IAsyncResult result) {
Console.WriteLine("My Important Variable was: {0}", result.AsyncState); // Prints 5
}
This is a problem I prefer to solve with anonymous delegates:
var someDataIdLikeToKeep = new object();
mySocket.BeginBlaBla(some, other, ar => {
mySocket.EndBlaBla(ar);
CallSomeFunc(someDataIdLikeToKeep);
}, null) //no longer passing state as we captured what we need in callback closure
It saves having to cast a state object in the receiving function.
When you call BeginReceive, you can pass any object as its last parameter. The same object will be made available to your callback through IAsyncResult's AsyncState property.
As MrMDavidson mentioned.
If you look at the overloads of BeginReceive you'll see the object parameter (named state)
You could pass an object array of your desired parameters to the state parameter and then deal with them later in the callback method.
client.BeginConnect(ipEndPoint, new AsyncCallback(ConnectedCallback), new object[] { parameter1, parameter2});
Let's say I have this method:
public static object CallMethod(Delegate method, params object[] args)
{
//more logic
return method.DynamicInvoke(args);
}
This below has worked fine for most scenarios, calling it like so (simple example):
Delegate methodCall = new Func<decimal,decimal>(Math.Ceiling);
object callResult = CallMethod(methodCall, myNumber);
However, I've run into a situation where I need to use this on a method that takes in a 'ref' parameter (WCF service call), which the Func class can not handle.
Delegate methodCall =
new Func<MyService.InputClass, MyService.CallResult>(service.DoWork);
Since I don't have a lot of experience dealing with delegates, what would be the easiest way of creating a delegate for the above method to pass on to mine?
This isn't my application so I don't have an easy way of testing it (I was just asked if I knew of a way of resolving the problem), but does this look like it should work?
Delegate methodCall = new Func<MyService.CallResult>(delegate() { return service.DoWork(ref myInput)});
object callResult = CallMethod(methodCall, null);
Given the following, when is foo bound?
System.Timer t = new System.Timer( (a)=>{
var foo = Messages.SelectedItem as FooBar;
});
Is it bound then the anonymous method is executed, or when the method is defined?
foo is not bound at all, as it's internal to the anonymous method. It will call Messages.SelectedItem. If Messages is an instance property, what is bound is the 'this' instance, which is used to get at Messages.
Never, because of the compile-time error you would get due the absence of a System.Timer class in the BCL. Assuming you wanted a System.Threading.Timer then the closure will be bound/captured at the moment this constructor is called i.e. the method is defined. If you want to bind it when the method is executed you need another constructor overload and pass a state.
var t = new System.Threading.Timer(a =>
{
var foo = a as FooBar;
}, Messages.SelectedItem, -1, -1);
Now when the callback runs it will use the Messages.SelectedItem value at the moment this callback executes.