C# object still exists after removing its reference - c#

I'm just curious how this works:
In my class Form1.cs I have declared an object static:
public static Class1 class1;
This is how the constructor of Class1 looks like:
public Class1()
{
Form1.class1 = null;
}
I expected to get a null reference exception in MS VS 2010
class1 = new Class1();
class1.showMSG();
But instead it just executes showMSG() (showMSG is not static) like I've never set the reference to class1 to null.
Any thoughts on this?

Well, you intialize it actually class1 = new Class1(); here, according to the code provided.
You first set it to null
Form1.class1 = null;
after
class1 = new Class1(); //INIT THE SAME (ACCORDING TO THE NAME) OBJECT
class1.showMSG(); //CALL A METHOD ON IT.
EDIT
According to edited question:
public Class1()
{
Form1.class1 = null;
}
doesn't reset anything as you're still inside a constructor, on exit from it actually object will be constructed and assigned to the same object you assigned null before.

Class1's constructor sets
Form1.class1 = null;
But when you execute
class1 = new Class1();
the assignment to class1 (which is the same class1) happens after the constructor executes. So Form1.class1 now has a value.

Maybe it's easiest to explain if you break up your last two lines, into:
var tmp = new Class1(); // makes class1 null
class1.showMSG(); // would raise exception, remove this line to proceed
class1 = tmp; // class1 is no longer null
class1.showMSG(); // no exception, instance exists to call method on

Related

How can I hold a WeakReference<Action> to a method of an instance until the instance is collected?

class Program
{
static void Main(string[] args)
{
var inst = new SomeClass();
var weakRef = new WeakReference<Action>(inst.DoSomething);
GC.Collect();
Console.WriteLine($"inst is alive = {inst != null} : weakRef.Target is alive = {weakRef.TryGetTarget(out Action callback)}");
Console.ReadLine();
}
}
public class SomeClass
{
public void DoSomething() { }
}
The output shows that inst is not null, but the reference that WeakReference<Action> points to is. I expect this is because a new Action is created that points to the instance method, rather than storing a reference to the instance's method itself.
How can I hold a weak reference to a method of an object instance for the duration that the instance is not yet garbage collected?
If you need that Action instance would not be collected before SomeClass instance, then you need to add reference from SomeClass instance to Action instance. It can be instance field of SomeClass that point to Action instance, but if you can not alter SomeClass definition, than you can use ConditionalWeakTable<TKey,TValue> class to attach field dynamically.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.CompilerServices;
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default)]
public class SomeClass {
public void DoSomething() { }
}
public static class DelegateKeeper {
private static ConditionalWeakTable<object, List<Delegate>> cwt = new ConditionalWeakTable<object, List<Delegate>>();
public static void KeepAlive(Delegate d) => cwt.GetOrCreateValue(d?.Target ?? throw new ArgumentNullException(nameof(d))).Add(d);
}
static class Program {
static void Main() {
SomeClass inst = new SomeClass();
Action a1 = inst.DoSomething;
DelegateKeeper.KeepAlive(a1);
Action a2 = inst.DoSomething;
WeakReference<SomeClass> winst = new WeakReference<SomeClass>(inst);
WeakReference<Action> wa1 = new WeakReference<Action>(a1);
WeakReference<Action> wa2 = new WeakReference<Action>(a2);
GC.Collect();
Console.WriteLine($"{winst.TryGetTarget(out _),5}:{wa1.TryGetTarget(out _),5}:{wa2.TryGetTarget(out _),5}");
GC.KeepAlive(a1);
GC.KeepAlive(a2);
GC.Collect();
Console.WriteLine($"{winst.TryGetTarget(out _),5}:{wa1.TryGetTarget(out _),5}:{wa2.TryGetTarget(out _),5}");
GC.KeepAlive(inst);
GC.Collect();
Console.WriteLine($"{winst.TryGetTarget(out _),5}:{wa1.TryGetTarget(out _),5}:{wa2.TryGetTarget(out _),5}");
}
}
Output:
True: True: True
True: True:False
False:False:False
tio.run
In DelegateKeeper class I use List<Delegate> as dependent object type, so you can keep multiple delegates per one class instance. I use Delegate.Target as key to the table, so you do not need to pass instance separately. This would not work with anonymous methods, since them likely to have compiler generated closure class in Target property. GetOrCreateValue get value bound to key or create new one using default constructor and add it to table automatically.
Creating an Action instance from a MethodGroup creates an instance that isn't attached in any way to the instance of the class that the method is a member of. That means that there is nothing keeping your Action rooted, and the GC will happily collect it.
If you store a reference to the Action as a member of the class, it will become rooted to the lifetime of that instance, preventing it from being collected as long as that instance is alive.
public class SomeClass
{
public SomeClass()
{
DoSomething = this.DoSomething_Internal ;
}
public Action DoSomething { get; }
private void DoSomething_Internal() { }
}
Note: I made the original DoSomething private, and renamed it to DoSomething_Internal, replacing the old DoSomething with a readonly property in order to keep the class signature as close as possible to your original class. You don't need to follow this pattern exactly, any reference to the Action stored in the class, including in a normal field, will do. Though you will still have to expose that reference somehow if you actually want to be able to use it.
You can test it like this:
var inst = new SomeClass();
var weakRef = new WeakReference<Action>(inst.DoSomething);
GC.Collect();
GC.WaitForPendingFinalizers(); // You should do this after forcing a GC, just in case there is still GC work being done in the background.
Console.WriteLine($"inst is alive = {inst != null} : weakRef.Target is alive = {weakRef.TryGetTarget(out Action callback1)}");
// These next 2 lines discard local variables, as Hans points out in the comments,
// DO NOT do this in production code. Please read the link he posted for more details.
inst = null; // discard the class instance
callback1 = null; // discard the temporary Action instance from TryGetTarget, otherwise it will act as a GC Root, preventing it from being collected later.
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine($"inst is alive = {inst != null} : weakRef.Target is alive = {weakRef.TryGetTarget(out Action callback2)}");
Which produces the following output:
inst is alive = True : weakRef.Target is alive = True
inst is alive = False : weakRef.Target is alive = False

Access Non Static Method inside Static Method AJAX

Here is my scenario: I am trying to get a value from frontend using AJAX and then want to use this in a non-static method for some calculations. But I am getting an error:
Object reference not set to an instance of an object
I know how to use non-static method/data members in a static method by creating obrect Reference that I did but still error is same.
Code:
[WebMethod]
[WebScript]
public static string refAssignments(getVal rf)
{
string value = rf.valueFromAJAX;
MyClass obj = new MyClass();
string result = obj.analyse(value);
}
Here Analyse() is a non-static method all I want is to use this method inside the static method refAssignments.
I tried earlier questions but wasn't successful! Can someone point where I am doing wrong
The problem isn't relevant with the Analyse method is non-static or not. Probably, rf object is null. Check the rf object;
if (rf != null)
{
string value = rf.valueFromAJAX;
MyClass obj = new MyClass();
string result = obj.analyse(value);
}
else
{
//Do something
}

Why object is not updating as NULL

When I am updating my obj as null its output is 30 but no exception but when I am updating obj.Age = 25 output is 25.
I am not getting the idea what is happening behind the scene.
Can someone explain why this is happening?
public class A
{
public int age;
}
class Program
{
public static void Test(A obj)
{
//obj = null;
//obj.age = 25;
}
static void Main(string[] args)
{
try
{
A obj = new A();
obj.age = 30;
Test(obj);
Console.WriteLine(obj.age);
}
catch (Exception)
{
throw;
}
}
}
Notice the method signature -
public static void Test(A obj)
The parameter is not passed as ref. When the reference types are passed as parameter, without specifying as ref. You can change the properties values within the object, but you cannot assign the object to point it to another memory location.
In simple words you cannot do -
obj = null OR obj = new A() OR obj = instanceOfAnotherObject
To be able to even change the object, you need to change the method signature and pass obj by ref -
public static void Test(ref A obj)
When you do obj = null; then you do not set the object to null but the reference to that object to null. As in your method Test the parameter is a new reference to the passed object, it does not affect the obj reference in Main and so setting obj to null in Test has only an effect in that method.
To do / see what you want you may want to change the parameter of Test to a ref parameter like so
public static void Test(ref A obj)
and then call Test like so
...
A obj = new A();
obj.age = 30;
Test(ref obj);
...
as now you actually modify the obj reference of the Main method.
When you do obj.age = 25; in Test (of course without setting obj to null in front of it) then you modify the same object as obj in Main points to and so when writing the age to the console you will see 25.
That is possible because it was passed by reference - if you replace A with e.g. int and pass that around then changing its value in Test will not be reflected in the output of Main as integers are passed by value. You may find reading this page and the subsequent pages to it helpful

Static variable initialization using new gives a code hazard

I am working on some code which is something like this:
class A
{
static SomeClass a = new Someclass("asfae");
}
Someclass contains the required constructor.
The code for this compiles fine without any warning. But I get a code hazard in system:
"The Someclass ctor has been called from static constructor and/or
static initialiser"
This code hazard part of system just to make it better by warning about possible flaws in the system or if system can get into bad state because of this.
I read somewhere on the web that static constructor/initialiser can get into deadlock in c# if they wait for a thread to finish. Does that have something to do with this?
I need to get rid of this warning how can i do this.
I can't make the member unstatic as it's used by a static function.
What should I do in this case , Need help.
You could hide it behind a property and initialize it on first use (not thread-safe);
class A
{
static SomeClass aField;
static SomeClass aProperty
{
get
{
if (aField == null) { aField = new Someclass("asfae"); }
return aField;
}
}
}
or use Lazy (thread-safe):
class A
{
static Lazy<SomeClass> a = new Lazy<SomeClass>(() => new Someclass("asfae"));
}
...or this very verbose thread safe version :)
class A
{
static SomeClass aField;
static object aFieldLock = new object();
static SomeClass aProperty
{
get
{
lock (aFieldLock)
{
if (aField == null) { aField = new Someclass("asfae"); }
return aField;
}
}
}
}
By initialising it as a static field, it behaves as it would in a static constructor, i.e. it probably gets initialised the first time an instance of your class is instantiated, but might happen earlier. If you want more control over exactly when the field is initialised, you could use Lazy<T>, e.g.:
{
static Lazy<SomeClass> a = new Lazy<SomeClass>(() => new Someclass("asfae"));
}
This way, you know that the initialisation of SomeClass will only happen the first time the field is accessed and its Value property called.
I think to understand your problem you need to know the difference between static constructors and type initializers, there is a great article from Jon Skeet about this issue:
http://csharpindepth.com/Articles/General/Beforefieldinit.aspx
The point is that following constructions are not the same, and there are difference in the behavior:
class Test
{
static object o = new object();
}
class Test
{
static object o;
static Test()
{
o = new object();
}
}
In any case, you could try to create a static constructor for your class to be able to have more control on this initialization, and maybe the warning will disappear.
If the member is only used by a static method, and only by this one, I would recommend you to put it in the scope if this static method and not as class member.

Prevent a Class having static instances of it created in C#

Is there anyway way to prevent a class having static instances of it created in C#. I don't think there is but it could be useful. E.g just some attribute to prevent it.
something like this
[NoStaticInstances]
public class MyClass {
}
so that
public static MyClass _myClass;
would cause an error?
There's no such thing as a "static instance" - there's only a static variable, which is assigned a value. And there's no way of preventing static variables of a particular type being declared, unless you make the type itself static, which will prevent any instances being created and any variables of that type from being declared.
Imagine if your desired feature did exist... how would you expect the following code to behave?
class Test
{
static object foo;
static void Main()
{
MyClass bar = new MyClass();
foo = bar;
}
}
Which line of that would cause an error, if any? If it's the assignment, imagine this instead:
class Test
{
static object foo;
static void Main()
{
MyClass bar = new MyClass();
object tmp = bar;
foo = tmp;
}
}
In short, I don't think you're going to be able to prevent static variables holding references to instances of your class. Out of interest, why do you want to?
What you can do is the following:
public class MyClass
{
public MyClass()
{
#if DEBUG // Only run in debug mode, because of performance.
StackTrace trace = new StackTrace();
var callingMethod = trace.GetFrames()[1].GetMethod();
if (callingMethod.IsStatic &&
callingMethod.Name == ".cctor")
{
throw new InvalidOperationException(
"You naughty boy!");
}
#endif
}
}
Static fields will 'normally' be created by static constructors. What the above code does is looking at the calling method to see if it is a static constructor and if that's the case, throw an exception.
Note however, that this check is quite fragile and smart users can easily work around this by refactoring the creation of this method to another method. In other words, I agree with every body else that there is no good way to do this.
Such a restriction would not make sense.
What if you write
static object something = new YourClass();
Not really, there is no language or compiler feature that supports this.
No, there's no way to dictate the scope or lifetime of object references in C#.

Categories

Resources