Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
Further, why is it that I have to new up a MyClass to use MyVoidAction?
See code below:
using System;
public class MyClass
{
public delegate void MyDeler();
public Action MyVoidAction;
}
class MainClass
{
static void Main()
{
MyClass.MyDeler d = () => Console.WriteLine("my deler");
d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
}
}
I looked up this answer: Accessibility between Action and Delegate
That cleared up a lot, but I'm not sure I'm 100% on this. So according to that answer, the delegate void MyDeler() defines a type, which confuses me because I imagine something like this:
using System;
class MainClass
{
class MyClass
{
public static class DelegateClass
{
public void DoDel() // isn't even legal?
{
Console.WriteLine("DoDel()");
}
}
}
static void Main()
{
//MyClass.DelegateClass d = new asdf // ??? something like this?
}
}
Help appreciated!
Let's demystify this:
When you declare MyDeler:
public delegate void MyDeler();
What you are doing is defining a type of method to which execution will be "delegated". In other words, you are saying there is method out there that follows this signature and I intend to keep references to it. In order for the compiler to identify these references, this type will be used.
It follows then that you will need to actually have a real pointer to the method, since this is just your "definition". That's why you will need a variable of type "MyDeler" to which you can assign the actual method to call:
MyClass.MyDeler d = () => Console.WriteLine("my deler");
This line is saying "create a variable named d of type MyClass.MyDeler that holds a reference to this inline method". From here on, when you call d(); the pointer will actually execute the inline method.
For the action:
public Action MyVoidAction;
You are now declaring a public property of the class. Therefore, you need an instance of the class before you can use this property.
The trick here is that Action is a known definition of a delegate. Microsoft has a built-in type that you can use instead of declaring your own void MyDeler();. It's essentially syntactical sugar but remember, it's still a type and as you have created a public property, you now need to assign it the method that will actually execute and as we discussed before, you need an instance:
MyClass meClass = new MyClass(); //Instance creation
meClass.MyVoidAction = () => Console.WriteLine("my void action"); //Tell your delegate what to delegate to.
meClass.MyVoidAction(); //Run the inline method!
I hope that helps.
MyDeler is a type declaration, not a variable declaration. You can't store things in it or assign to it.
To create a field for storing a MyDeler instance, add this line to MyClass:
public MyDeler MyDelerField;
Now you can assign to it.
Why is MyDeler "static", as in I can access MyDeler through the class name, but I can't explicity say public "static" delegate void MyDeler(), nor can I access d through an instance of MyClass, as in new MyClass.d()?
The declaration of MyDeler declares a type within MyClass. It's similar to declaring any other nested type, like:
class MyClass
{
public class MyNestedClass { }
}
It is a member of the type MyClass, not of any actual instance of MyClass, nor even of the class MyClass as a static member would be.
A nested type is neither "instance" nor "static", because it's part of the type system, not part of the class itself.
why is it that I have to new up a MyClass to use MyVoidAction?
Because MyVoidAction is a member of the class, and is an instance member. So you are required to have an instance of the class to access it.
the delegate void MyDeler() defines a type, which confuses me because I imagine something like this
Your declaration in that example of public static class DelegateClass is doing something completely different. An unfortunate aspect of C# is the use of static to refer to a variety of different things. It's not quite as bad as in Java, but it can still be confusing (as you're finding out).
In that declaration, the use of the word static does not make DelegateClass a "static member" of the containing type MyClass. Instead, the word static as part of a class declaration means that the entire class will contain only static members.
Thus, when you declare DoDel() without the static keyword, you are attempting to declare an instance member, i.e. that method, in a class where you've promised to declare only static members. If you add static to the method declaration, it would compile.
Not that doing so would make the DelegateClass class in that example similar to the MyVoidAction member in your other example. It's still a type declaration, declaring a nested type within the MyClass class, and would still follow the rules for types, not class members. But I hope that at least explains to you why the example that's confusing you works the way it does.
Action and a delegate of a method with no parameters and that returns void are formally the same thing.
If u take a look to: https://msdn.microsoft.com/en-us/library/system.action(v=vs.110).aspx you can see that:
You can use this delegate to pass a method as a parameter without
explicitly declaring a custom delegate.
I hope this example helps:
public delegate void DelegateMyDeler(); //This is a custom delegate
public class MyClass
{
public DelegateMyDeler MyDeler; //This use your custom delegate
public Action MyVoidAction; // This use Action delegate
}
class MainClass
{
static void Main()
{
// MyClass.MyDeler d = () => Console.WriteLine("my deler"); // Now this is not allowed too!
// d();
// MyClass.MyVoidAction mva1 = () => Console.WriteLine("my void action"); // not allowed, why?
MyClass meClass = new MyClass();
meClass.MyDeler = () => Console.WriteLine("my deler");
meClass.MyDeler();
meClass.MyVoidAction = () => Console.WriteLine("my void action");
meClass.MyVoidAction();
//but you can do (you custom delegate is defined out of the class in this case
//so you have not to add the class prefix):
DelegateMyDeler d = () => Console.WriteLine("my deler 2");
d();
// or
DelegateMyDeler d3 = () => Console.WriteLine("my deler 3");
d3.Invoke();
// and in a real case, for example:
DelegateMyDeler undeterminedMethod;
int x = 3;
switch (x)
{
case 1:
undeterminedMethod = deler1;
break;
case 2:
undeterminedMethod = deler2;
break;
case 3:
undeterminedMethod = deler3;
break;
default:
undeterminedMethod = null;
break;
}
undeterminedMethod?.Invoke(); //In case x is minor than 1 or major than 3, nothing happens
}
static void deler1() { Console.WriteLine("my deler 1"); }
static void deler2() { Console.WriteLine("my deler 2"); }
static void deler3() { Console.WriteLine("my deler 3"); }
}
Related
I'm studying the uses of this and I think I understand it, at least partially, like when to solve ambiguity and to call methods from the "current" class, but one example from the book I'm reading(Head First C#) is giving me a hard time:
public void SpeakTo(Elephant whoToTalkTo, string message) {
whoToTalkTo.TellMe(message, this);
}
In this method, is it safe to say that the this has the function of always refering to whatever object calls the method SpeakTo(), regardless of which class the call is written in?
No... Actually, this in your context refers to the object on which SpeakTo is defined, not the object which calls it.
Let's put it this way:
Object speaker is of the class Speaker which defines the SpeakTo
method,
Object caller is calling the speaker.SpeakTo(), and
Object whoToTalkTo is of the class which defines the TellMe(string, Speaker)
As you can see, whoToTalkTo is expecting the Speaker class instance. Then, the speaker object is precisely that, and it is free to pass this as the argument.
Now we can construct a larger example in which these relations are becoming more obvious:
class Speaker
{
public int Data { get; set; }
public void SpeakTo(Elephant whoToTalkTo, string message)
{
// Passing current instance of this class as the argument
whoToTalkTo.TellMe(message, this);
}
}
This Speaker class contains a piece of state. Now I will use the whoToTalkTo object to change that state:
class Talker
{
public void TellMe(string message, Speaker speaker)
{
speaker.Data = message.Length;
}
}
This implementation is changing the state of one particular object which was passed to it.
Now the ultimate caller comes to the picture, the one which actually selects the Speaker object which will be subjected to the TellMe() method:
class Caller
{
public void DoWork()
{
Talker talker = new Talker();
Speaker one = new Speaker();
Speaker two = new Speaker();
// This sets one.Data to length of "something"
one.SpeakTo(talker, "something");
// This sets two.Data to length of "else"
two.SpeakTo(talker, "else");
Console.WriteLine(one.Data);
Console.WriteLine(two.Data);
}
}
This code will print values 9 and 4, which indicates that the whoToTalkTo has actually been modifying the state of two distinct objects.
In this method, is it safe to say that the "this" has the function of always refering to whatever object calls the method "SpeakTo()", regardless of which class the call is written in?
Nope. this does not refer to the object that calls SpeakTo. It refers to the object on which SpeakTo is called.
I will use some code to clarify this point
class Foo {
public static void Main(String[] args) {
var foo = new Foo();
foo.MyMethod();
}
public void MyMethod() {
var bar = new Bar();
bar.SpeakTo(anElephant, "Hello");
}
}
class Bar {
public void SpeakTo(Elephant whoToTalkTo, string message) {
whoToTalkTo.TellMe(message, this);
}
}
According to your statement, this refers to the foo variable that's created in the main method. This is not the case. this actually refers to bar. i.e. the object that's before the method name.
this refers to the current object of the class which has method SpeakTo.
consider the following example:
public class A
{
public void SpeakTo(Elephant whoToTalkTo, string message) {
whoToTalkTo.TellMe(message, this);
}
}
Now if you instantiate an object of A and calls the method SpeakTo it will be like:
A obj = new A();
obj.SpeakTo();
In the method SpeakTo, this refers to the current object, i.e. obj.
The signature of method TellMe should look like:
public void TellMe(string message, A objOfA)
This is a sample code to declare UnityAction array.
And assign each method on the elements.
public class Car {
int _wheels;
public Car(int wheels){_wheels = wheels;}
public void Go(){
Debug.Log ("GO:"+_wheels);
}
}
public class UnityEventTest : MonoBehaviour {
void Start()
{
UnityAction []action = new UnityAction[2];
//case #1
action[0] = new UnityAction(FuncA);
//case #2
action[1] = FuncB;
action[0].Invoke ();
action[1].Invoke ();
//----------------------------------
Car aCar = new Car(1);
Car bCar = new Car(2);
Car []carList = new Car[2];
carList[0] = aCar;
carList[1] = bCar;
carList[0].Go();
carList[1].Go();
}
void FuncA(){Debug.Log ("A");}
void FuncB(){Debug.Log ("B");}
}
Both of Case #1 and Case #2 work well.
Output:
A
B
GO:1
GO:2
But, I don't understand why case #2 works?
There may be no UnityAction instance in each array elements.
The code just assign class's method. And, As far as I know C# delegate(like UnityAction) is a reference data type.
So I think case #2 should make some error or can not be assigned.
Unlike the car's case below, I think a method name is not an instance.
Ok, first thing is notice that UnityAction() is a void delegate.
If you look the Declaration you can confirm that:
//From Assembly sourcecode:
namespace UnityEngine.Events
{
public delegate void UnityAction ();
}
So in Case#1 you are creating a void delegate from FuncA, since FuncA returns void there are no problem doing that (you can try to change void FuncA to int FuncA and see what happens :) )!
Now in Case#2 you are directly assigning FuncB (which is a method) to a UnityAction(delegate) without using any kind of explicit or implicit cast!
So how this can work? Well, the answer seem to be a thing called delegate-method-group-conversion that :
"...simplifies the syntax used to assign a method to a delegate. Method
group conversion allows you to assign the name of a method to a
delegate, without the use new or explicitly invoking the delegate's
constructor."
So, without any special syntax you can assign a method to a delegate, in this particular case, a UnityAction.
I have been using javascript and I made a lot of use of functions inside of functions. I tried this in C# but it seems they don't exist. If I have the following:
public abc() {
}
How can I code a method d() that can only be called
from inside the method the method abc() ?
I wouldn't worry so much about the restriction of access to a method on the method level but more class level, you can use private to restrict access of the method to that specific class.
Another alternative would be to use lambdas/anonymous methods, or if you're using C# 4.0, Action/Tasks to create them inside your method.
An example of an anonymous method using a delegate (C# 1/2/3/4) for your specific example (incl. I need an action that can take a string parameter and return a string?) would be something like this:
delegate string MyDelegate(string);
public void abc() {
// Your code..
MyDelegate d = delegate(string a) { return a + "whatever"; };
var str = d("hello");
}
.. using C# 3/4:
public void abc() {
// Your code..
Func<string, string> d = (a) => { return a + "whatever"; };
var str = d("hello");
}
.. using a more ideal solution through private method:
private string d(string a)
{
return a + "whatever";
}
public void abc()
{
// Your code..
var str = d("hello");
}
Based on your comment for another answer: I would just like to have this at the bottom of the method and then call it from some earlier code.
This won't be possible, you would need to define a variable for your method using either delegates or Actions and so it would need to be fully initialised by time you call it. You wouldn't then be able to define this at the bottom of your method. A much better option would be to simply create a new private method on your class and call that.
It is not the way to define classes, but you could do:
public abc() {
Action d = () => {
// define your method
};
d();
}
You cannot declare a method inside another method, but you can create anonymous functions inside methods:
public void abc()
{
Action d = () => { ... };
// ...
d();
}
... that can only be called from inside the method the method abc() ?
The method can only be called if you have a reference to it. If you don't store the reference elsewhere then you should be fine.
how can I pass and return a string to the action?
Use a Func instead of an Action:
Func<string, string> d = s => {
return s + "foo";
};
The reason I would like to do this is to make my code more readable.
It's good to try to make your code more readable but I think this change will make it less readable. I suggest you use ordinary methods, and not anonymous functions. You can make them private so that they cannot be called from outside your class.
Use action delegates. More effective than you did.
public abc() {
Action <int> GetInt = (i) =>
{
//Write code here
Console.Writeline("Your integer is: {0}", i);
};
GetInt(10);
}
Action is a delegate so you can give parameter as a method, not variable. Action delegate encapsulates a method that has no parameters and does not return a value. Check it from MSDN.
Yes, they are called delegates and anonymous methods.
Delegate signatures must be predefined outside of the method for the body to be assigned, so it's not exactly like a function. You would first declare a delegate:
class MyClass {
public delegate boolean Decider(string message);
/* ... */
}
And then in MyClass.MyMethod you can say Decider IsAllLowerCase = /* method name or anonymous method */; and then use it with var result = IsAllLowerCase(s);.
The good news is that .NET already has delegate definitions for most signatures you could possibly need. System.Action has assorted signatures for methods which do not return anything, and System.Func is for the ones that do.
As shown elsewhere,
Action<int, string> a = (n, s) => { for(var i=0; i<n; i++) Console.WriteLine(s);};
Allows you to call a( /* inputs */ ); as if it was a local variable. (stuff) => { code } is "lambda expression" or an anonymous method, you can also just pass a name of a method (if the signature matches):
Action<string> a = Console.WriteLine;
If you want to return something, use Func:
Func<bool, string> f = (b) => { return b.ToString(); };
Allows you to call var result = f(b); in the same way.
As a footnote, delegates are a fun part of C#/.NET but usually, the way to control access is to make another method inside your class, and declare it private. If your issue is name conflicts, then you might want to refactor. For example, you can group methods in another class declared inside your original class (nested classes are supported) or move them to another class entirely.
You can use action delegates
public abc() {
Action action = () =>
{
//Your code here
}
action();
}
Edit: To pass parameter
public abc() {
Action <string>action = (str) =>
{
//Your code here
};
}
action("hello");
Using Func to return a value
public void abc() {
Func<string, string> func = (str) => { return "You sent " + str; };
string str = func("hello");
}
You CAN create a nested class:
public class ContainingClass
{
public static class NestedClass
{
public static void Method2()
{
}
public static void Method3()
{
}
}
}
Then yu can call:
ContainingClass.NestedClass.Method2();
or
ContainingClass.NestedClass.Method3();
I wouldn't recommend this though. Usually it's a bad idea to have public nested types.
I have referenced one DLL (I have source code of this) say Dll_A in which there is a function
private void uploadPic(int a)
In my main project, I have a function say
private void passMe(int b)
{
}
I need to pass the above function (passMe) to uploadPic function in Dll_A, how can I do that? Is it possible?
I am able to use functions of the Dll_A from my main project, so instantiating isn't a problem, I just need a way to pass function.
===
Thanks, giving it a try. If some can edit code below
//code in main project picbackman.cs
public delegate void delObj(int v);
private void uploadSome(string path, string fName, string str)
{
delObj del1 = new delObj(updatePValue);
UploadFileResponse response = boxProvider1.UploadFiles(args1, folderString, ((Picbackman.BoxProvider.delObj)( del1)));
}
//code in different dll which is referenced in main project //Dll_A
public delegate void delObj(int v);
public UploadFileResponse UploadFiles(string[] filePathes,string folderId, delObj d)
{}
First of all your method will need to accept a delegate as one of it's parameters. That would be something like
private void uploadPic(Action<int> func,int a){
//at some point do func(someInt);
}
at another point declare anothe method or function
public class someClasse {
public vois passMe(int b){
...
}
}
First of all notice that the access modifier has changed. if they are not in the same class you will need to be able to access one from the other so they can't both be private and since they are in different assemblies internal won't work either.
when you need the delegate do like this
var obj = new someClass();
var myInt = 5; //or whatever the value is
uploadPic(obj.passMe,myInt);
notice that the method is used with out arguments. When using a method without arguments the compiler will try and convert it to a suitable delegate.
I'd recommend you not to use delegate but stick with Func/Action they are delegates but more generic
public delegate void DelObj1();
public delegate void DelObj2()
public void F(){};
var del1 = new DelObj1(F);
var del2 = new DelObj2(F);
you can't pass a del1 where a DelObj2 is needed even though you use the same method for each. You will not have that issue if you use Action/Function
Action del1 = F;
Action del2 = F;
The reason is that DelObj1 and DelObj2 are two distinct classes with the same base class Ie they are siblings in the type tree. Using Action the type is the same for both del1 and del2
You should have a look at Delegates.
From the documentation:
A delegate is a type that references a method. Once a delegate is
assigned a method, it behaves exactly like that method. The delegate
method can be used like any other method, with parameters and a return
value
and
Delegates allow methods to be passed as parameters
So in your case you should be able to do something like this:
// define the delegate
public delegate int PictureDelegate(int value)
// define your passMe function (in the class MyClass for example)
public int passMe(int value)
{
return value + 1;
}
// when you want to use it
MyClass myInstance = new MyClass();
PictureDelegate passFunc = new PictureDelegate(myInstance.passMe);
myDll.uploadPic(passFunc, 12);
Say I have 2 classes, class A and class B. Class A creates an instance of Class B. Class A has a function that I would like to pass into a method from Class B.
class A {
void Main(string[] args) {
B classB=new B();
DelegateCaller(new delFunction(classB.TheFunction()); // <-- Won't compile (method name expected)
DelegateCaller(new delFunction(B.TheFunction()); // <-- Won't compile (object reference is req'd)
}
public delegate string delFunction();
public DelegateCaller(delFunction func) {
System.Console.WriteLine(func());
}
}
class B {
public string TheFunction() {
return "I'm Printing!!!";
}
}
I'm not sure if it a syntax issue or it's just something I can't do. Maybe I need to define the delegate in B, but reference it in A? What about B's this pointer?
It's just a syntax issue; get rid of the parentheses after classB.TheFunction - they indicate that you wish to invoke the method.
DelegateCaller(new delFunction(classB.TheFunction));
Do note that there is an implicit conversion available from a method-group, so you can just do:
DelegateCaller(classB.TheFunction);
Also note that creating your own delegate-type in this case is unnecessary; you could just use the in-built Func<string> type.
EDIT: As Darin Dimitrov points out, there is also the unrelated issue of calling an instance method as though it were a static method.
Try like this:
class A
{
static void Main()
{
B classB = new B();
DelegateCaller(classB.TheFunction);
}
public delegate string delFunction();
public static void DelegateCaller(delFunction func)
{
Console.WriteLine(func());
}
}
class B
{
public string TheFunction()
{
return "I'm Printing!!!";
}
}
Let me elaborate about the different changes I've made to your initial code:
TheFunction in class B needs to be public so that you can access it from class A
The DelegateCaller method in class A should be static and not necessarily return a value (declare it as void) if you want to call it from the static Main method.
The definition of the delFunction delegate should return a string.
Take the parenthesis off the end of TheFunction. You want the method, not the result of a call to the method.
If you want to capture an instance method for usage in a general purpose fashion you should use Delegate.CreateDelegate(Type,MethodInfo). This is nice as it allows you to create an "open delegate" meaning it isn't bound to an instance and can take any instance that is a ClassB. It makes reflection quite fast if you know the type information, as this method will perform much faster than the equivalent statement using MethodInfo.Invoke.
DelegateCaller(new delFunction(B.TheFunction());
Should be
DelegateCaller(new delFunction(B.TheFunction);
To use classB.TheFunction you would need to make TheFunction static. You pass in the function with no parens.