As far as I understand the concept of delegates, they simply point to a method. Then when I'm feeling lucky I can go out and invoke the method my delegate is pointing to, right?
Given is the following code:
class Program
{
static void Main(string[] args)
{
Func<MyClass> myAct = GetAct();
Method(myAct);
}
private static Func<MyClass> GetAct()
{
MyClass obj = new MyClass()
{
Prop1 = 5
};
Func<MyClass> myAct = new Func<MyClass>(
() =>
{
MyClass obj2 = new MyClass();
MyClass2 obj3 = new MyClass2()
{
Prop3 = 25,
Prop4 = "test"
};
obj2.Prop2 = ((obj.Prop1 + 5) * obj3.Prop3)
.ToString() + obj3.Prop4;
return obj2;
});
return myAct;
}
static void Method(Delegate func)
{
GC.Collect();
GC.WaitForPendingFinalizers();
var result = func.DynamicInvoke();
}
}
class MyClass
{
public int Prop1 { get; set; }
public string Prop2 { get; set; }
}
class MyClass2
{
public int Prop3 { get; set; }
public string Prop4 { get; set; }
}
Now my delegate myAct (in this case a Func<MyClass>) is pointing to an anonymous function which performs some simple assignation of variables. Nothing special so far.
We invoke the delegate.
Everything went fine, just as we expected. But the question is why? If the delegate just simply points to the anonymous method AND a garbage collection was done, how could the CLR know what obj and it's values are?
Where is the reference to obj stored, to be available when the function is called? Inside the delegate?
Your anonymous method is defined within the scope of GetAct() so CLR makes scope variables available to the anonymous method.
It's similar to how an instance variable is usable by member methods.
Also, review the pitfalls of using closures: http://msmvps.com/blogs/peterritchie/archive/2010/11/03/deep-dive-on-closure-pitfals.aspx
Related
public class testClass
{
testClass x = null;
public testClass()
{
x = this;
}
~testClass()
{
System.Console.WriteLine("I was destroyed");
}
}
public static class objectInMemory
{
public static int Main(string[] args)
{
testClass a = new testClass();
a = null;
System.Console.WriteLine("a=null");
System.Console.WriteLine("something");
System.Console.WriteLine("last line");
return 0;
}
}
So.. In the code, how can I assign the instantiated testClass object to another variable after "a = null;" For example let "b = thatObject'sAddress;"?
It is not a problem, just came across my mind.
You could use this to get a pointer to your object and use the debugger to check what you want to know:
Memory address of an object in C#
Garbage Collector basics can be looked up here:
https://learn.microsoft.com/en-us/dotnet/standard/garbage-collection/fundamentals
I have an interface that extends some other interface, like this:
interface IBase
{
int Id { get; set; }
string Name { get; set; }
}
interface IExtended : IBase
{
bool IsChecked { get; set; }
}
Then I use base interface as a parameter in a delegate function that is also a parameter to class constructor, like this:
public class SomeClass
{
private IBase _model;
private Func<IBase, string> _handler;
public SomeClass(IBase model, Func<IBase, string> handler)
{
_model = model;
_handler = handler;
}
public string ExecuteHandler()
{
return _handler(model);
}
}
Interface implementations:
public class BaseImplementation : IBase
{
int Id { get; set; }
string Name { get; set; }
public BaseImplementation(int id, string name)
{
Id = id;
Name = name;
}
}
public class ExtendedImplementation : IExtended
{
int Id { get; set; }
string Name { get; set; }
bool IsChecked { get; set; }
public BaseImplementation(int id, string name, bool isChecked)
{
Id = id;
Name = name;
IsChecked = isChecked;
}
}
Intended use:
BaseImplemetation baseModel = new BaseImplementation(1, "base");
ExtendedImplemetation extendedModel = new ExtendedImplementation(2, "extended", true);
SomeClass someClass1 = new SomeClass(baseModel, (IBase arg) => {
Console.Write("Remember, " + arg.name + ", YOLO!");
});
SomeClass someClass2 = new SomeClass(extendedModel, (IExtended arg) => {
Console.Write(arg.name + ", YOLO! You're " + (arg.IsChecked) ? "checked!" : "not checked!");
});
string res1 = someClass1.ExecuteHandler();
string res2 = someClass2.ExecuteHandler();
But that ( doesn't work, even though implementation of IExtended would necessarily implement everything that is defined by IBase interface. Why is that so and how would I bypass this and get the result I want?
EDIT:
I think I got it now.
I thought that Func<IBase, string> is equal to Func<IExtended, string> because IExtended of course implements everything that IBase does, so there should be no problem, right? Implementation as I wanted it to be and is listed in my example would of course work just fine.
BUT! The problem is that someClass2 can't be constructed like that because, as #Servy mentioned, delegate function could do something like this:
SomeClass someClassWrong = new SomeClass(baseModel, (IExtended arg) => {
if (arg.IsChecked) {
// gotcha, baseModel doesn't have IsChecked property!
}
});
EDIT 2:
Thank you everybody for you help and sorry for constant editing and giving wrong example sof what I want :D
But that doesn't work, even though implementation of IExtended would necessarily implement everything that is defined by IBase interface. Why is that so and how would I bypass this and get the result I want?
When SomeClass invokes that delegate it might not actually pass an IExtended instance. It's allowed to provide any IBase instance as the parameter, so if it provides one that doesn't implement IExtended, then what would you expect your delegate to do?
If SomeClass is always going to pass an IExtended instance, then modify the delegate it accepts in its constructor accordingly, so that the callers always know they're getting an IExtended instance as a parameter.
You can simply define a delegate that knows the IBase is really an IExtended:
SomeClass someClass = new SomeClass((IBase arg) => { (arg as IExtended).DoSomethingOnlyExtendedKnowsAbout(); });
This is potentially unsafe, but if you somehow can enforce that the arg passed to that specific lamda will always be an IExtended then there is no harm. You could also provide a safety mechanism in the lambda itself and manage it accordingly up the call stack:
SomeClass someClass = new SomeClass((IBase arg) => { (arg as IExtended)?.DoSomethingOnlyExtendedKnowsAbout(); });
I don't see the problem. Based on the code you have, the following works as intended:
public class SomeClass
{
public SomeClass(Func<IBase, string> handlerFcn)
{
// something gets done
this.Handler=handlerFcn;
}
public Func<IBase, string> Handler { get; set; }
}
public static class Program
{
static void Main(string[] args)
{
var s1 = new SomeClass((x) => x.SomeMethod());
var xt = new ExtendedClass();
var result = s1.Handler(xt);
// result = "yolo extended edition!"
}
}
I think you were trying to use the concrete class ExtendedClass in the lambda definition and that won't work unless you define it as a closure.
In c# I used to init my class by calling default constructor. You can mention () after class name
var class = new MyClass()
{
Property= 1,
Property2 = "test"
}
But last time I see examples without (). Like this
var class = new MyClass
{
Property= 1,
Property2 = "test"
}
Is there any difference with and without ()?
This feature is called Object Initializer and it's been introduced in C#3.0.
When you use it, the () are redundant, so there is no difference between your two code samples
There are no differences. If you use resharper, it mark this () as redundant.
You can use () or not, It depends on your style.
As you see in the IL Code they are identical:
internal class Program
{
public class MyClass
{
public int Property
{
get;
set;
}
public string Property2
{
get;
set;
}
}
private static void Main(string[] args)
{
Program.MyClass expr_06 = new Program.MyClass();
expr_06.Property = 1;
expr_06.Property2 = "test";
Program.MyClass expr_20 = new Program.MyClass();
expr_20.Property = 1;
expr_20.Property2 = "test";
}
}
Wrapping a reference to the list's enumerator inside a class seems to change its behavior. Example with an anonymous class:
public static void Main()
{
var list = new List<int>() { 1, 2, 3 };
var an = new { E = list.GetEnumerator() };
while (an.E.MoveNext())
{
Debug.Write(an.E.Current);
}
}
I would expect this to print "123", but it only prints zero and never terminates. The same example with a concrete class:
public static void Main()
{
var list = new List<int>() { 1, 2, 3 };
var an = new Foo()
{
E = list.GetEnumerator()
};
while (an.E.MoveNext())
{
Debug.Write(an.E.Current);
}
}
public class Foo
{
public List<int>.Enumerator E { get; set; }
}
What's going on?
I tested it and for me it does not work with your concrete class either.
The reason is that List<T>.Enumerator is a mutable struct and an.E is a property.
The compiler generates a backing field for each auto-property like this:
public class Foo
{
private List<int>.Enumerator _E;
public List<int>.Enumerator get_E() { return E; }
public void set_E(List<int>.Enumerator value) { E = value; }
}
A struct is a value-type, so every-time you access an.E you get a copy of that value.
When you call MoveNext() or Current, you call it on that copy and this copy is mutated.
The next time you access an.E to call MoveNext() or Current you get a fresh copy of the not-yet-iterated enumerator.
And an.E.Current is 0 instead of 1 because - again - you get a fresh enumerator that MoveNext() was not yet called upon.
If you want to store a reference of the list's enumerator you could declare your class Foo with a property of type IEnumerator<int>:
public class Foo
{
public IEnumerator<int> E { get; set; }
}
If you assign E = list.GetEnumerator(); now, the enumerator gets boxed and a reference instead of a value is stored.
Say I have a class declared as follows:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass()
{
}
public void FuncA(int n)
{
//irrelevant code here
}
public void FuncB(int n)
{
//other irrelevant code here
}
}
I want to be able to use this class like this
ExampleClass excl = new ExampleClass() { Do = FuncA }
or
ExampleClass excl = new ExampleClass() { Do = excl.FuncA }
or
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }
I can compile the second option there, but I get a "Delegate to an instance method cannot have null 'this'." exception when I hit that code. The third one doesn't even make sense, because FuncA isn't static.
In my actual code, there will be maybe 10-15 different functions it could get tied to, and I could be adding or removing them at any time, so I don't want to have to have a large switch or it-else statement. Additionally, being able assign a value to 'Do' when instantiating the class is very convenient.
Am I just using incorrect syntax? Is there a better way to create a class and assign an action in one line? Should I just man up and manage a huge switch statement?
You have to create the instance of the class and later set the property to the instance member. Something like:
ExampleClass excl = new ExampleClass();
excl.Do = excl.FuncA;
For your line:
ExampleClass excl = new ExampleClass() { Do = FuncA }
FuncA is not visible without an instance of the class.
For:
ExampleClass excl = new ExampleClass() { Do = excl.FuncA }
Instance has not yet been created that is why you are getting the exception for null reference.
For:
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA }
FuncA is not a static method, you can't access it with the class name.
In object initializer syntax you cannot access the variable being initialized before it is definitely assigned:
ExampleClass excl = new ExampleClass()
{
Do = excl.FuncA //excl is unavailable here
}
Read Object and Collection Initializers (C# Programming Guide) for more info.
You could do the following, for example:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass(bool useA)
{
if (useA)
Do = FuncA;
else
Do = FuncB;
}
public void FuncA(int n)
{
//irrelevant code here
}
public void FuncB(int n)
{
//other irrelevant code here
}
}
and use it:
ExampleClass exclA = new ExampleClass(true);
ExampleClass exclB = new ExampleClass(false);
Another idea is if these functions may be declared as static (i.e. they don't need any instance members of the ExampleClass), then this would work:
public class ExampleClass
{
public Action<int> Do { get; set; }
public ExampleClass() { }
public static void FuncA(int n) { /*...*/}
public static void FuncB(int n) { /*...*/}
}
and use it the way you want:
ExampleClass excl = new ExampleClass() { Do = ExampleClass.FuncA };
If you have extension methods make sure that those values are not null before invoking the extension methods or handle nulls inside the extension methods.
For example
public static ExtensionClass
{
public static bool RunExtensionMethod(this object myObject)
{
var someExecutionOnMyObject = myObject.IsValid();
//the above line would invoke the exception when myObject is null
return someExecutionOnMyObject ;
}
}
public void CallingMethod()
{
var myObject = getMyObject();
if(myObject.RunExtensionMethod()) //This would cause "delete to an instance method cannot have null" if myObject is null
{
}
}
To handle this scenario handle nulls and assert nulls if you own the extension class.
public static ExtensionClass
{
public static bool RunExtensionMethod(this object myObject)
{
if(myObject == null) throw new ArgumentNullException(nameof(myObject));
var someExecutionOnMyObject = myObject.IsValid();
return someExecutionOnMyObject ;
}
}
public void CallingMethod()
{
var myObject = getMyObject();
if(myObject != null && myObject.RunExtensionMethod())
{
}
}