C# Action Variable Scope and Null References - c#

I can declare an Action and pass it a method on an instance object which modifies that object's internal state, then call the method and see that the private instance variables have changed. But if I create the Action, then null out the object it has a reference to a method on I don't get a null reference exception when I invoke the Action, but obviously I do if I try to access the object.
How can it be changing anything if there is nothing there to change?
A contrived example where I create a builder object which has a public void BuildWall method which just increments the number of walls it has built (a private integer variable). Why can I call buildWallAction after I have set builder to null or else how is the Action modifying the object if the object doesn't need to exist in order to call the action?
Thanks in advance :)
class Program
{
static void Main(string[] args)
{
Builder builder = new Builder("Jim");
Console.WriteLine(builder.ToString());
Action buildWallAction = builder.BuildWall;
builder = null; //no more builder to change via BuildWall()
//starts work
buildWallAction(); //these calls modify _wallsBuilt on the builder object
buildWallAction(); //but if we set it to null we can still call them just fine
Console.WriteLine(builder.GetBuildingStatus()); //we will only get an exception here if builder is null
Console.ReadKey();
}
}
public class Builder
{
private string _name;
private int _wallsBuilt;
public Builder(string name)
{
_name = name;
_wallsBuilt = 0;
}
public void BuildWall()
{
_wallsBuilt++;
}
public string GetBuildingStatus()
{
string msg = $"{_name} has built {_wallsBuilt} walls.";
return msg;
}
}

Your builder variable isn't the instance, it is a reference to the instance. So setting the variable to null, doesn't 'erase' the instance, you only get rid of the reference so you cannot access it anymore.
The buildWallAction variable is a reference to the method BuildWall of the instance. This is no way directly related to the builder variable. Setting the builder variable to null doesn't do anything to the buildWallAction variable.

Related

No constructor found while instantiating Assembly on runtime

After loading a DLL and obtaining a type, I get an exception trying to instantiate it:
Assembly dll = Assembly.LoadFrom(#"C:\path\file.dll");
Type type = dll.GetType("namespace.CustomClass");
object obj = Activator.CreateInstance(type); // <-- System.MissingMethodException
"No constructor with 0 parameters defined for this object" (average translation)
Exploring the loaded type, I can see the DeclaredConstrunctors -> {Void .ctor()}
But calling type.GetConstructors() I get an empty array (I guess that means that only default constructor exists?)
I neither found any factory class that returns an object of my class, or an getInstance function.
Any idea how to proceed?
There are a few possibilities here.
The first is that the all of the defined parameters take parameters. There's no guarantee that every class has a 0-parameter constructor. Here's an example of some code that produces this error:
public class SomeCons
{
public SomeCons(string cons)
{
}
}
static void Main(string[] args)
{
object result = Activator.CreateInstance(typeof(SomeCons));
}
The second possibility namespace.CustomClass has a private constructor. The following code produces similar behavior to what you saw. I also included an example of how to find the actual constructor - you want to use Binding Flags.
private class NoCons
{
private NoCons()
{
}
}
static void Main(string[] args)
{
// As you saw, this shows one declared constructor
Type exploratory = typeof(NoCons);
// Returns nothing
ConstructorInfo[] constructors = typeof(NoCons).GetConstructors();
// Returns 1 constructor
constructors = typeof(NoCons).GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
}
Please note that it may be important to understand exactly why namespace.CustomClass has a private constructor in the first place. That's actually a really common thing to do if you're trying to define a Singleton, in which case you probably don't want to call the constructor directly.
For a singleton like this:
private class NoCons
{
private NoCons()
{
}
private static NoCons _instance;
public static NoCons Instance
{
get
{
if (_instance == null)
{
_instance = new NoCons();
}
return _instance;
}
}
}
try something like this:
Type exploratory = typeof(NoCons);
PropertyInfo singletonProperty = exploratory.GetProperties(BindingFlags.Static | BindingFlags.Public).FirstOrDefault(prop => prop.Name.Contains("Instance"));
string name = singletonProperty.GetGetMethod().Name;
var noCons = exploratory.GetMethod(name).Invoke(null, null) as NoCons;
The DLL had a related OCX file placed in another folder.
The file has been registered using:
Regsvr32 .\file.ocx
After that, I've been able to instantiate an object calling:
using Microsoft.VisualBasic;
MyAssemblyName object = (MyAssemblyName) Interaction.CreateObject( "MyNamespace.MyAssemblyName", "");

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

C# Singleton Thread-safe variables

I have referred to Jon Skeet's article here (http://csharpindepth.com/articles/general/singleton.aspx), the sixth version.
However, I have some private variables that I want initialized once, and be used by methods in this supposedly singleton class. I initialized them in the private constructor, but soon found out, that they are null when invoking the methods, in a multi-threaded scenario (Task.Run).
When debugging, I observed that the private constructor doesn't called twice (which should be) when I call out for an "Instance", and so I assume that my private variables, shouldn't be null at that point in time already (succeeding "Instance" calls).
Any idea on how should I declare, initialize, and use these variables?
public sealed class Singleton
{
private static readonly Lazy<Singleton> lazy =
new Lazy<Singleton>(() => new Singleton());
public static Singleton Instance { get { return lazy.Value; } }
// my private variables
private readonly string _plantCode;
private Singleton()
{
var appSettings = ConfigurationManager.AppSettings;
string _plantCode = appSettings["PlantCode"] ?? "Not Found";
}
public SomeMethod()
{
var temp = _plantCode; // <== _plantCode becomes null here!
}
}
This is the problem:
string _plantCode = appSettings["PlantCode"] ?? "Not Found";
That isn't assigning to the instance variable - it's declaring a new local variable. You just want:
_plantCode = appSettings["PlantCode"] ?? "Not Found";
(This would happen with the same code in a normal class, by the way - it has nothing to do with the fact that it's a singleton.)

Ninject Memoize Instances in Singleton Scope

I'm using Ninject to instantiate some objects with a constructor arg passed, e.g.:
class MyClass
{
public MyClass(string myArg)
{
this.myArg = myArg;
}
}
The number of instances I need of this class won't be known until runtime, but what I want to do is ensure that each variation of myArg results in a different singleton instance (so asking for the same value twice returns the same instance, but different args return different instances).
Does anyone know of a good, preferably built-in, way of doing this?
I found an article written for an older version of Ninject How To Ensure One Instance per Variation of Activation Parameters but was hoping there'd be a tidier solution for the newer version.
Edit
Here's what I went with, adapted from Akim's answer below:
private readonly ConcurrentBag<string> scopeParameters = new ConcurrentBag<string>();
internal object ParameterScope(IContext context, string parameterName)
{
var param = context.Parameters.First(p => p.Name.Equals(parameterName));
var paramValue = param.GetValue(context, context.Request.Target) as string;
paramValue = string.Intern(paramValue);
if (paramValue != null && !scopeParameters.Contains(paramValue))
{
scopeParameters.Add(paramValue);
}
return paramValue;
}
public override void Load()
{
Bind<MyClass>()
.ToSelf()
.InScope(c => ParameterScope(c, "myArg"));
Bind<IMyClassFactory>()
.ToFactory();
}
You could achieve require behaviour by providing custom scope using IBindingNamedWithOrOnSyntax<T> InScope(Func<IContext, object> scope) method for MyClass binding
Indicates that instances activated via the binding should be re-used
as long as the object returned by the provided callback remains alive
(that is, has not been garbage collected).
So, you need to return value of first constructor argument from Func<IContext, object> scopeand make sure that garbage-collector would not collect it.
Here is a snippet:
public class Module : NinjectModule
{
// stores string myArg to protect from CG
ConcurrentBag<string> ParamSet = new ConcurrentBag<string>();
public override void Load()
{
Bind<MyClass>()
.ToSelf()
// custom scope
.InScope((context) =>
{
// get first constructor argument
var param = context.Parameters.First().GetValue(context, context.Request.Target) as string;
// retrieves system reference to string
param = string.Intern(param);
// protect value from CG
if(param != null && ParamSet.Contains(param))
{
// protect from GC
ParamSet.Add(param);
}
// make Ninject to return same instance for this argument
return param;
});
}
}
ps: full sample code with unittests

Categories

Resources