Creating multiple objects in loop - c#

This is my first time, so... be gentle ;) Welcome community!
Here's my problem. I have to create multiple objects inside a loop. But I don't know how to do it. Already tried doing it this way:
List<myClass> ObjectList = new List<MyClass>();
and then :
ObjectList.Add(new MyClass(a,b));
Class is with descriptor and params "a" and "b" are set.
So, I'm looking for this :
class myClass
{
int a;
int b;
public MyClass(int A, int B)
{
a=A;
b=B;
}
class Main()
{
Random r=new Random();
MyClass a1 = new MyClass(r.Next(0,11));
MyClass a2 = new MyClass(r.Next(0,11));
MyClass a3 = new MyClass(r.Next(0,11));
MyClass a4 = new MyClass(r.Next(0,11));
MyClass a5 = new MyClass(r.Next(0,11));
MyClass a6 = new MyClass(r.Next(0,11));
}
}
And I have to find a way to create these objects in the loop, cause I cannot know how many of these will be, as I'm reading a matrix from a file.

There is a common solution to the situation where you want to initialise something by repeatedly attempting to acquire an item from a source until the source runs out.
This is called a "loop-and-a-half" construct (and it's a proper "structured" construct, since it is a loop with a single exit).
The general approach goes like this:
while (true)
{
attempt to obtain next item;
if (no more items available)
break loop;
add item to collection;
}
A general implementation in C# might look like this:
class MyClass
{
}
class MyInitData
{
}
static class Program
{
static void Main(string[] args)
{
var list = new List<MyClass>();
while (true)
{
var initData = GetNextItem(); // Returns null when no more items are available.
if (initData == null) // No more items available.
break;
list.Add(CreateMyClassFromInitData(initData));
}
}
static MyInitData GetNextItem() // Returns null when no more items are available.
{
// Code to return next item. Implementation omitted here.
return null;
}
static MyClass CreateMyClassFromInitData(MyInitData initData)
{
// Create a new MyClass from initData. Implementation omitted here.
return new MyClass();
}
}
As another - simpler - example, here's how you might go about reading number strings from a text file and converting them into a list of ints, using a loop-and-a-half:
var list = new List<int>();
using (var reader = File.OpenText("MyFileName.txt"))
{
while (true)
{
string line = reader.ReadLine();
if (line == null)
break;
list.Add(int.Parse(line));
}
}

Related

C# Dictionary<int,Object> updates by itself

I'll try to resume everything as much as possible:
I have a class that creates a dictionary (let's call it secondary dictionary) with the initial values of some of the elements of another dictionary, (for simplicity, let's call it the main dictionary and this class does this only once) and then a thread that checks every x miliseconds against this main dictionary, that's being regularly updated every y miliseconds, for any changes on the elements that where stored in the initialization phase.
My problem is, that when I want to compare the values of element1 in the main dictionary against the value of element1 in the secondary dictionary, they're always the same, (I undersatnd that, until the main dictionary is nnot updated, both values will be the same, but when the main dictionary gets updated, so does the second, immediately, without me doing anything)
I've tried ConcurrentDictionaries, using locks, a combination of boths, creating a new element in the initialize functions instead of passing it directly, but nothing seems to work
class Checker
{
private static bool secondaryDictionaryHasChanged = false;
private static ConcurrentDictionary<int, ValueDTO> secondaryDictionary = new ConcurrentDictionary<int, ValueDTO>();
public Checker()
{
initSecondaryDictionary();
Thread checkChangedValsThread = new Thread(() => checkChangedValsThreadFunction(1000));
checkChangedValsThread.Start();
}
public void initSecondaryDictionary()
{
Object MainLock = new Object();
lock (MainLock)
{
Object secondaryLock = new Object();
lock (secondaryLock)
{
foreach (var variable in Maindictionary)
{
if (variable.isElegibleValue)
{
ValueDTO ValueDTOToAdd = new ValueDTO();
ValueDTOToAdd.EligibleVar = variable;
if (variable.contextVariables.Count > 0)
{
List<Var> contextVariablesToAdd = new List<Var>();
foreach (var item in variable.contextVariables)
{
contextVariablesToAdd.Add(getVarFromMainDictionary(item));
}
ValueDTOToAdd.ContextVars = contextVariablesToAdd;
}
secondaryDictionary.TryAdd(ValueDTOToAdd.EligibleVar.varCode, ValueDTOToAdd);
}
}
}
}
secondaryDictionaryHasChanged = false;
}
public void checkChangedValsThreadFunction(int checkTime)
{
while (true)
{
try
{
if (!secondaryDictionaryHasChanged)
{
Thread.Sleep(checkTime);
Object mainLock = new Object();
lock (mainLock)
{
Object secondaryLock = new Object();
lock (secondaryLock)
{
foreach (var item in secondaryDictionary)
{
ValueDTO secondaryDictionaryDTO = item.Value;
Var variableInSecondary = secondaryDictionaryDTO.EligibleVar;
Var variableInMain = getVarFromMainDictionary(item.Value.EligibleVar.varID);
int valueInMain = variableInMain.getIntValue();
int valueInSecondary = variableInSecondary.getIntValue();
if (valueInMain != valueInSecondary)
{
//IT NEVER ENTERS THIS HERE
}
}
}
}
}
}
catch (Exception e)
{
throw new Exception("Some exception: " + e.Message);
}
}
}
}
internal class ValueDTO
{
public Var EligibleVar { get; set; }
public List<Var> ContextVars { get; set; }
}
internal class Var
{
public int varCode { get; set; }
public string varID { get; set; }
}
I add a reduced version of the code I have the thing is that it will never go inside that if(mainValue != secondaryValue)
any help or info about where I'm going wrong will be deeply appreciated
As fildor already said, you have one object and two references to it.
To simplify your problem I created a short sample:
using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
public class Example
{
class Person
{
public string Name
{
get;
set;
}
}
public static void Main()
{
var myPerson = new Person();
myPerson.Name = "User1";
var list1 = new List<Person>();
var list2 = new List<Person>();
// put a reference to myPerson into each of the lists
list1.Add(myPerson);
list2.Add(myPerson);
// get the reference to myPerson from list1
var myPersonInList1 = list1[0]
myPersonInList1.Name = "User2";
// this will print User2 because there is only one person object
Console.WriteLine(list2[0].Name);
}
}
Basically no matter where you pass the Person, it will always be a reference to the Person instance you created. All changes to it will apply to the object behind the reference. All references point to the same object.
A bit more in depth knowledge very simplified, but I hope you'll get the point:
There is a stack and a heap storage. The stack contains value types and references and the heap contains objects.
Stack:
Variable | Value
--------------------
myPerson | #abc123
list1[0] | #abc123
list2[0] | #abc123
myInt | 42
Heap:
Address | Value
-------------------
abc123 | { Name: "User2" }
Now every time you create a variable pointing to myPerson, you only create a new entry in the stack, pointing to the same object in the heap. Now, of course when you update the object behind the reference and set its name to "User1", all references will display the change.

"Reflection": Method with "params" does not initialize my custom Objects

I have a custom class from which I create over 200 objects for a Gui.
In my main class with my business logic I want to apply the instantiation of all my objects, attach them to an event handler and set their Name. Instead of doing all this by hand for every object I thought to create a method that takes as parameters a "params" list of my objects. The problem is that this method seems to work out a "copy" of my objects instead the reference of those. What I have so far is:
My object base class:
public class MyObject
{
... // this works
}
My business class now (what works):
public class Logic
{
public MyObject Object001, Object002,... Object200; // note that they are not instantiated yet
public Logic()
{
Object001 = new MyObject();
Object001.Name = nameof(Object001);
Object001.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
Object002 = new MyObject();
Object002.Name = nameof(Object002);
Object002.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
...
Object200 = new MyObject();
Object200.Name = nameof(Object200 );
Object200.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
}
}
My desired business class (what has not worked):
public class Logic
{
public MyObject Object001, Object002,... Object200; // note that they are not instantiated yet
public Logic()
{
InstantiateAllObjects(Object001, Object002, ..., Object200); // here my 200 objects!
}
private void InstantiateAllObjects(params MyObject[] list)
{
for (int i=0; i<list.Length; i++)
{
// if(list[i]==Object001) Console.WriteLine("Object001== null?: " + (Object001 == null)); --> this executes for EVERY object, instead for only Object001!!
MyObject obj = list[i];
obj = new MyObject();
obj.Name = nameof(obj); // why "nameof(list[i])" didn't work?
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
// if (list[i] == Object001) Console.WriteLine("Object001== null?: " + (Object001== null)); --> this executes again for EVERY object AND (Object001== null) is ALWAYS true!!
}
}
}
Can anybody explain me why my method seems not to create my objects?
Thanks in advance for your time and help!
EDIT
In my opinion, the problem seems to be i have to pass a reference to these declared objects in the 'params' list of my method... is it possible? how? I tried to use the modifiers "out" and "ref" near the "params" in the method, but with "params" seems not to be possible...
EDIT2
Following some suggestions I created in my class: logic an object list:
MyObject[] list = new MyObject[] { Object001, Object002, ..., Object200 };
InstantiateAllObjects(ref list);
and modified my method as per private void InstantiateAllObjects(ref MyObject[] list) iterating inside over list[i], but unfortunately with the same wrong result...
and also tried
List<MyObject> list = new List<MyObject>() { Object001, Object002, ..., Object200 };
InstantiateAllObjects(ref list);
and modified my method as per private void InstantiateAllObjects(ref List<MyObject> list) iterating inside over list[i], but unfortunately also with the same wrong result...
Forget about all those Object001, Object002 etc fields. Just use a new List<MyObject>() and add your objects into it inside the for-loop in your InstantiateAllObjects.
public class Logic
{
private readonly List<MyObject> allMyObjects; // note that they still are not instantiated yet
public Logic()
{
cont int amount = 200;
allMyObjects = new List<MyObject>(amount); // reserve space, but all are still null
InstantiateAllObjects(allMyObjects, amount);
}
private void InstantiateAllObjects(List<MyObject> list, int amount)
{
for (int i=0; i<amount; i++)
{
MyObject obj = new MyObject();
obj.Name = "Object" + (i+1).ToString("000");
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
list.Add(obj); // place the newly created object in the list
}
}
}
Your original test if(list[i]==Object001) fires every time, because both list[i] (for every i) and Object001 are null.
Also note that you can have multiple references to one instance of your MyObject (this already happens when you pass the reference as parameter to some method). The fact that one of those is called "Object001" is not important and in fact unknown to the instance. That is why nameof(list[i]) cannot return "Object001".
Another try, based on Hans Kesting'a answer and anna's statement
2) the name of every object will be (very) different one to another,
it is here just that i used the indexes 001...200 to concept the idea,
To avoid any trouble with accessing the fields and to regard what you wrote in the comments, no getter/setter is used and everything is public. Not the best approach but well, compared to handling 200 separate objects...
public class Logic
{
public List<MyObject> MyObjectList;
public List<string> MyObjectNames;
public Logic()
{
var anotherClass = new AnotherClass();
MyObjectNames = new List<string>() {"Object01", "Object02", "Object03"}; // either add your names here...
MyObjectNames.Add("Object04"); // or add additional names this way
//MyObjectNames.AddRange(anotherNameList); // or add another list or use Linq or whatever
MyObjectList = anotherClass.InstantiateAllObjects(MyObjectNames);
}
}
public class AnotherClass
{
public List<MyObject> InstantiateAllObjects(List<string> nameList)
{
var objectList = new List<MyObject>(nameList.Count);
foreach (var name in nameList)
{
objectList.Add(new MyObject(){Name = name});
}
return objectList;
}
}
Does this meet your requirements?
If you prefer a Dictionary, it's similar:
public class Logic
{
public Dictionary<string, MyObject> MyObjectDict;
public List<string> MyObjectNames;
public Logic()
{
var anotherClass = new AnotherClass();
MyObjectNames = new List<string>() { "Object01", "Object02", "Object03" }; // either add your names here...
MyObjectNames.Add("Object04"); // or add additional names this way
//MyObjectNames.AddRange(anotherNameList); // or add another list or use Linq or whatever
MyObjectDict = anotherClass.InstantiateAllObjects(MyObjectNames);
// objects in dict can be accessed directly by their names:
var object01 = MyObjectDict["Object01"];
}
}
// You can access in derived classes or any other classes
public class DerivedLogic : Logic
{
public void SomeFunc()
{
var object01 = MyObjectDict["Object01"];
}
public void SomeOtherFunc(string objectName)
{
var object01 = MyObjectDict[objectName];
}
}
public class AnotherClass
{
public Dictionary<string, MyObject> InstantiateAllObjects(List<string> nameList)
{
var objectList = new Dictionary<string, MyObject>(nameList.Count);
foreach (var name in nameList)
{
// check if object with name does not already exist.
if(!objectList.ContainsKey(name)
{
// For your property changed assignment, you can separate the object creation and DIctionary/List assignment
var obj = new MyObject() { Name = name };
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
objectList.Add(name, obj);
}
// else .... doe something
}
return objectList;
}
}
All of those arguments are being passed by value. You're passing the references, but the InstantiateAllObjects method can't change the values of any of the fields.
Simplifying this a bit, it's a little like having code like this:
string x = "Original value";
// This copies the value of x into the array
string[] array = new string[] { x };
// This changes the array element, but doesn't affect the x variable at all
array[0] = "Different value";
// Still prints "Original value", because x hasn't changed
Console.WriteLine(x);
As noted in comments, using a list is likely to be a much better approach than lots of different fields here.
Use a class (can be the same as the one with the logic) to hold your MyObject Fields, pass it into a function that uses reflection to populate the fields.
// Class with Fields
public class MyObjectCollection
{
public MyObject Object001;
public MyObject ObjTwo;
}
public class Logic
{
// Init logic
public void Initialise(object controls)
{
Type targType = typeof(MyObject);
var t = controls.GetType();
// iterate all fields of type MyObject
foreach(var fi in t.GetFields().Where(f=>f.FieldType == targType))
{
// initialise as required.
var o = new MyObject();
o.Name = fi.Name;
fi.SetValue(controls, o);
}
}
}
If the field name is not enough for the object name you could use Attributes on the fields to direct initialisation.
This should do the job. It is a reflection-based approach and what it does is:
find all public instance fields
use only those whose name contains Object
create a new instance of MyObject and store that in the field
public void InstantiateAllObjects()
{
foreach (FieldInfo field in this.GetType()
.GetFields(BindingFlags.Public | BindingFlags.Instance)
.Where(x => x.Name.Contains("Object")))
{
MyObject obj= new MyObject();
obj.PropertyChanged += (s, e) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(null));
field.SetValue(this, obj);
}
}
If you add above method to your Logic class, you can then call it without having to explicitly pass Object001, Object002 etc. to it.
public class Logic
{
public MyObject Object001, Object002, ... Object200;
public Logic()
{
this.InstantiateAllObjects();
}
}
EDIT: Differently named fields
If the fields do not share a common prefix (that is, if they are not all named Object + ...), there are other ways to get the fields:
.Where(x => x.FieldType == typeof(MyObject))
yields only the fields whose type is MyObject.
You could also create an attribute
[AttributeUsage(AttributeTargets.Field)]
public sealed class FieldIWantToSetAttribute : Attribute { }
and apply that to all fields you want to set, e.g.
public class Logic
{
[FieldIWantToSet] public MyObject Object001; // will be set
[FieldIWantToSet] public MyObject Foo; // will be set
public MyObject Bar; // will not be set
}
Then, change the Where to
.Where(x => x.GetCustomAttribute<FieldIWantToSet>() != null)
Please however note that 1. you should definitely use caching. Reflection without caching is expensive, and 2. please overthink your design - why exactly do you feel the need to expose 200 fields for every other class to see?

Using reflection to get rid of the first two parameters in the function?

I have the following code. Is it possible to use reflection to get rid of the first two parameters since the information can be found in the Action assign (Or Expression), which will always have the form of b.P... = a.P...?
class A { .... }; var a = new A { P1 = .... } // class A and B are totally different clas
class B { .... }; var b = new B { P1 = .... } // But they have some properties with the same names
....
AssignAndDoSth(a.P1, b.P1, () => b.P1 = a.P1);
private void AssignAndDoSth<T>(T curr, T prev, Action assign) // assign can be Expression
{
if (!EqualityComparer<T>.Default.Equals(curr, prev))
{
assign();
Do(prev);
....
}
}
The short answer would be "I strongly advise against it"; in reality, this is actually an instance method of a compiler-generated capture class; so you would need to deconstruct the IL of the target method, and evaluate that IL against the fields of the target instance. Not good. What that actually looks like is something like:
var ctx = new SomeType();
ctx.a = new A { P1 = .... };
ctx.b = new B { P1 = .... };
AssignAndDoSth(a.P1, b.P1, new Action(ctx.SomeMethod));
...
class SomeType {
public A a;
public B b;
public void SomeMethod()
{
b.P1 = a.P1;
}
}
The other approach would be to refactor to an Expression<Action> - but that doesn't change the work involved much - it just presents a more friendly API (relatively speaking).
Either way, all that inspection will have a non-trivial performance cost.
An expression tree may not contain an assignment operator, but can contain operator ==
static void AssignAndDoSomething<T>(T curr, T prev, Expression<Func<bool>> assign)
{
var logExpr = assign.Body as System.Linq.Expressions.BinaryExpression;
//output rid of the first parameter
Console.WriteLine(logExpr.Left);
//output rid of the second parameter
Console.WriteLine(logExpr.Right);
//assign first parameter
Expression.Lambda<Action>(Expression.Assign(logExpr.Left, Expression.Constant(curr))).Compile()();
//assign second parameter
Expression.Lambda<Action>(Expression.Assign(logExpr.Right, Expression.Constant(prev))).Compile()();
}
class A
{
public int P1;
}
class B
{
public int P1;
}
var a = new A();
var b = new B();
AssignAndDoSomething(a.P1, b.P1, () => b.P1 == a.P1);

Create deep copy of List<object> [duplicate]

I'm trying to make a deep copy of a generic list, and am wondering if there is any other way then creating the copying method and actually copying over each member one at a time. I have a class that looks somewhat like this:
public class Data
{
private string comment;
public string Comment
{
get { return comment; }
set { comment = value; }
}
private List<double> traceData;
public List<double> TraceData
{
get { return traceData; }
set { traceData = value; }
}
}
And I have a list of the above data, i.e List<Data>. What I'm trying to do is plot a trace data of the subset of List onto a graph, possibly with some scaling or sweeping on the data. I obviously don't need to plot everything in the list because they don't fit into the screen.
I initially tried getting the subset of the list using the List.GetRange() method, but it seems that the underneath List<double> is being shallow copied instead of deep copied. When I get the subset again using List.GetRange(), I get previously modified data, not the raw data retrieved elsewhere.
Can anyone give me a direction on how to approach this? Thanks a lot.
The idiomatic way to approach this in C# is to implement ICloneable on your Data, and write a Clone method that does the deep copy (and then presumably a Enumerable.CloneRange method that can clone part of your list at once.) There isn't any built-in trick or framework method to make it easier than that.
Unless memory and performance are a real concern, I suggest that you try hard to redesign it to operate on immutable Data objects, though, instead. It'll wind up much simpler.
You can try this
public static object DeepCopy(object obj)
{
if (obj == null)
return null;
Type type = obj.GetType();
if (type.IsValueType || type == typeof(string))
{
return obj;
}
else if (type.IsArray)
{
Type elementType = Type.GetType(
type.FullName.Replace("[]", string.Empty));
var array = obj as Array;
Array copied = Array.CreateInstance(elementType, array.Length);
for (int i = 0; i < array.Length; i++)
{
copied.SetValue(DeepCopy(array.GetValue(i)), i);
}
return Convert.ChangeType(copied, obj.GetType());
}
else if (type.IsClass)
{
object toret = Activator.CreateInstance(obj.GetType());
FieldInfo[] fields = type.GetFields(BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.Instance);
foreach (FieldInfo field in fields)
{
object fieldValue = field.GetValue(obj);
if (fieldValue == null)
continue;
field.SetValue(toret, DeepCopy(fieldValue));
}
return toret;
}
else
throw new ArgumentException("Unknown type");
}
Thanks to DetoX83 article on code project.
If IClonable way is too tricky for you. I suggest converting to something and back. It can be done with BinaryFormatter or a Json Converter like Servicestack.Text since it is the fastest one in .Net.
Code should be something like this:
MyClass mc = new MyClass();
string json = mc.ToJson();
MyClass mcCloned = json.FromJson<MyClass>();
mcCloned will not reference mc.
The most easiest (but dirty) way is to implement ICloneable by your class and use next extension method:
public static IEnumerable<T> Clone<T>(this IEnumerable<T> collection) where T : ICloneable
{
return collection.Select(item => (T)item.Clone());
}
Usage:
var list = new List<Data> { new Data { Comment = "comment", TraceData = new List { 1, 2, 3 } };
var newList = list.Clone();
another thing you can do is mark your class as serializable and use binary serialization.
Here is a working example
public class Program
{
[Serializable]
public class Test
{
public int Id { get; set; }
public Test()
{
}
}
public static void Main()
{
//create a list of 10 Test objects with Id's 0-10
List<Test> firstList = Enumerable.Range(0,10).Select( x => new Test { Id = x } ).ToList();
using (var stream = new System.IO.MemoryStream())
{
var binaryFormatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter();
binaryFormatter.Serialize(stream, firstList); //serialize to stream
stream.Position = 0;
//deserialize from stream.
List<Test> secondList = binaryFormatter.Deserialize(stream) as List<Test>;
}
Console.ReadKey();
}
}
If you make your objects immutable you don't need to worry about passing around copies of them, then you could do something like:
var toPlot = list.Where(d => d.ShouldBePlotted());
Since your collection is mutable, you need to implement the deep copy programmatically:
public class Data
{
public string Comment { get; set; }
public List<double> TraceData { get; set; }
public Data DeepCopy()
{
return new Data
{
Comment = this.Comment,
TraceData = this.TraceData != null
? new List<double>(this.TraceData)
: null;
}
}
}
The Comment field can be shallow copied because its already an immutable class. You need to create a new list for TraceData, but the elements themselves are immutable and require no special handling to copy them.
When I get the subset again using
List.GetRange(), I get previously
modified data, not the raw data
retrieved elsewhere.
Use your new DeepCopy method as such:
var pointsInRange = dataPoints
.Select(x => x.DeepCopy())
.GetRange(start, length);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DeepListCopy_testingSome
{
class Program
{
static void Main(string[] args)
{
List<int> list1 = new List<int>();
List<int> list2 = new List<int>();
//populate list1
for (int i = 0; i < 20; i++)
{
list1.Add(1);
}
///////
Console.WriteLine("\n int in each list1 element is:\n");
///////
foreach (int i in list1)
{
Console.WriteLine(" list1 elements: {0}", i);
list2.Add(1);
}
///////
Console.WriteLine("\n int in each list2 element is:\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" list2 elements: {0}", i);
}
///////enter code here
for (int i = 0; i < list2.Count; i++)
{
list2[i] = 2;
}
///////
Console.WriteLine("\n Printing list1 and list2 respectively to show\n"
+ " there is two independent lists,i e, two differens"
+ "\n memory locations after modifying list2\n\n");
foreach (int i in list1)
{
Console.WriteLine(" Printing list1 elements: {0}", i);
}
///////
Console.WriteLine("\n\n");
///////
foreach (int i in list2)
{
Console.WriteLine(" Printing list2 elements: {0}", i);
}
Console.ReadKey();
}//end of Static void Main
}//end of class
}
One quick and generic way to deeply serialize an object is to use JSON.net. The following extension method allows serializing of a list of any arbitrary objects, but is able to skip Entity Framework navigation properties, since these may lead to circular dependencies and unwanted data fetches.
Method
public static List<T> DeepClone<T>(this IList<T> list, bool ignoreVirtualProps = false)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
if (ignoreVirtualProps)
{
settings.ContractResolver = new IgnoreNavigationPropsResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Formatting.Indented;
}
var serialized = JsonConvert.SerializeObject(list, settings);
return JsonConvert.DeserializeObject<List<T>>(serialized);
}
Usage
var clonedList = list.DeepClone();
By default, JSON.NET serializes only public properties. If private properties must be also cloned, this solution can be used.
This method allows for quick (de)serialization of complex hierarchies of objects.

Altering references within a reference parameter

I am trying to pass an array to a method. The array contains objects which need to be nulled. The method would simply null each object in a loop. I need this to reflect back in the caller.
Sample code (code goodness & minor syntactical issues can be ignored):
public class ABC
{
...
}
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
var arrayOfNullableObjects = new ABC[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
}
private void NullingFunction(ABC[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i] = null;
}
}
Clearly upon returning, toBeNulledObj1 & toBeNulledObj2 are not null but retain their older values though arrayOfNullableObjects now has two null objects. I realise that ref & out only apply to the collection parameter (here, arrayOfNullableObjects which doesn't even need a ref). I tried passing them in as params instead of a collection but that doesn't help, either (ref & params cannot be combined).
Question: How can I alter each/any object in a collection of objects within a method such that the change is visible to the caller? I am not altering the collection itself. Please note, I am not changing the contents/members of toBeNulledObj1 but the reference itself (to either null or a new object).
Solution #1: Unsafe code
One solution is using a unsafe code. You have to think twice before using it, and I do not know if you will be happy with my answer, but here it is.
static private void SomeMethod()
{
ABC toBeNulledObj1 = new ABC();
ABC toBeNulledObj2 = new ABC();
IntPtr[] arrayOfNullableObjects = new IntPtr[] { MakeReference(ref toBeNulledObj1), MakeReference(ref toBeNulledObj2) };
NullingFunction(arrayOfNullableObjects);
}
static private void NullingFunction(IntPtr[] arrayOfNullableObjects)
{
foreach (IntPtr reference in arrayOfNullableObjects)
ClearReference(reference);
}
/// <summary>
/// Makes the reference to the reference value of a reference type.
/// </summary>
static unsafe private IntPtr MakeReference<T>(ref T value)
where T: class
{
TypedReference reference = __makeref(value);
return *(IntPtr*)&reference;
}
/// <summary>
/// Clears the reference to a reference type, using a reference to that reference value.
/// </summary>
static unsafe private void ClearReference(IntPtr reference)
{
if (sizeof(IntPtr) == 4)
*((int*)reference) = 0;
else
*((long*)reference) = 0;
}
Solution #2: Anonymous class
The second solution could be done by using an anonymous class which holds your data. The fields inside this anonymous class are cleared. A disadvantage is that you have a second class and the reference to this class also should to be cleared. (This can be done by adding ref to o and in the NullingFunction set o to null.) Of course you can also use a predefined class, but his solution is the closest to your code in your OP.
public static void SomeMethod()
{
var container = new
{
toBeNulledObj1 = new ABC(),
toBeNulledObj2 = new ABC(),
};
NullingFunction(container);
}
private static void NullingFunction<T>(T container)
where T : class
{
if (container == null)
return;
foreach(FieldInfo f in container.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
if (f.FieldType.IsClass)
f.SetValue(container, null);
}
When you say you want to set them to null, do you mean that you want to destroy the object?
C# has automatic garbage collection, so as soon as an object goes out of scope (that is, when no other objects make reference to it), the garbage collector will destroy it.
In the code above, the label "tobeNulledObj1" still refers to an object, and your array also points to it before you call the NullingFunction.
After you call the NullingFunction, you still have one reference pointing to the object (that is, tobeNulledObj1). If you set tobeNulledObj1 to null, then the Garbage Collector will collect it.
EDIT: I second cheedep's question - what is it exactly that you are trying to do? What do you want your variables to hold at the end?
If function A holds a reference to a variable i.e:
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
And does not pass this into function B:
private NullingFunction(ABC[] arrayOfNullableObjects)
Then there is nothing that function B can do to change the reference that toBeNulledObj1 / 2 points to.
Since ref is not allowed along with params (as you mentioned):
private void NullingFunction(ref params ABC[] arrayOfNullableObjects)
{
for (int i = 0; i < arrayOfNullableObjects.Length; i++)
{
arrayOfNullableObjects[i] = null;
}
}
The available alternative is to create overloads e.g.:
private void SomeMethod()
{
var toBeNulledObj1 = new ABC();
var toBeNulledObj2 = new ABC();
NullingFunction(ref toBeNulledObj1, ref toBeNulledObj2);
Console.ReadKey();
}
private void NullingFunction(ref ABC one)
{
one = null;
}
private void NullingFunction(ref ABC one, ref ABC two)
{
one = null;
two = null;
}
Is wrapping acceptable?
class Wrapped<T> where T : new() {
private T val = new T();
...
public void Nullify() { val = null; }
}
private void SomeMethod()
{
var toBeNulledObj1 = new Wrapped<ABC>();
var toBeNulledObj2 = new Wrapped<ABC>();
var arrayOfNullableObjects = new Wrapped<ABC>[]{toBeNulledObj1 ,toBeNulledObj2};
NullingFunction(arrayOfNullableObjects);
Debug.Assert(toBeNulledObj1.Get() == null);
// Or...
Debug.Assert(toBeNulledObj1.IsDefined == false);
// Or...
Debug.Assert(toBeNulledObj1.IsNull == true);
}
private void NullingFunction(Wrapped<ABC>[] arrayOfNullableObjects)
{
for(int i = 0; i< arrayOfNullableObjects.Length ; i++)
{
arrayOfNullableObjects[i].Nullify();
}
}
(Disclaimer: hand-compiled code :) may contain errors)
If you need it as a general pattern, you can make NullingFunction parametric (T, U), with a constaint where U: Wrapped<T>
The idea is to make something similar to Nullable for ref types, or something that looks like a smart pointer, if you are familiar with C++.
Thus, wrapper could have T Get() (or an implicit conversion to T) to get out the value, an IsDefined property, and so on.

Categories