var list1 = new List<obj>();
var list2 = new List<obj>();
var item = new obj();
list1.Add(item);
list1.Add(item);
is there a way in c# to set all references in the current application to null if one reference that has the same reference value got set to null?
for example when i do list[0]=null or item=null, i want to set any reference in the current application that holds the same reference value to null so that the GC handles them, at the same time i dont want this behaviour for all Types, is there such thing in c#?
to get the idea
if i say
list1[0] = null
i want it at the same time to mean
list2[0] = null;
item = null;
There isn't a way to automatically set other variables to null, but if your point is to get the object garbage collected even though you still have other references to it, you can do that.
You need to use weak references. Weak references are documented here
You need to introduce an additional layer of indirection in your memory references. The simplest way would be to create a Nullable<T> type for classes:
public class Nullable<T> where T : class
{
public T Value { get; set; }
public Nullable(T initial)
{
this.Value = initial;
}
}
You could then use this type to wrap your objects:
var list1 = new List<Nullable<object>>();
var list2 = new List<Nullable<object>>();
var item = new Nullable<object>(new object());
list1.Add(item);
list2.Add(item);
item.Value = null; // clears value from all collections
Related
I've came across this code:
var rectangle = new Rectangle(420, 69);
var newOne = rectangle with { Width = 420 }
I was wondering about with keyword in C# code. What is it for? And how can it be used? And what benefits does it bring to the language?
It's an operator used in expressions for easier duplication of an object, overriding some of it's public properties/fields (optional)
with expression - MSDN
Currently it can only be used with records. But maybe there will be no such restriction in the future (assumption).
Here's an example how it can be used:
// Declaring a record with a public property and a private field
record WithOperatorTest
{
private int _myPrivateField;
public int MyProperty { get; set; }
public void SetMyPrivateField(int a = 5)
{
_myPrivateField = a;
}
}
Now let's see how with operator can be used:
var firstInstance = new WithOperatorTest
{
MyProperty = 10
};
firstInstance.SetMyPrivateField(11);
var copiedInstance = firstInstance with { };
// now "copiedInstance" also has "MyProperty" set to 10 and "_myPrivateField" set to 11.
var thirdCopiedInstance = copiedInstance with { MyProperty = 100 };
// now "thirdCopiedInstance " also has "MyProperty" set to 100 and "_myPrivateField" set to 11.
thirdCopiedInstance.SetMyPrivateField(-1);
// now "thirdCopiedInstance " also has "MyProperty" set to 100 and "_myPrivateField" set to -1.
NOTE for reference types from MSDN:
In the case of a reference-type member, only the reference to a member instance is copied when an operand is copied. Both the copy and original operand have access to the same reference-type instance.
That logic can be modified by modifying the copy constructor of a record type. Quote from MSDN:
By default, the copy constructor is implicit, that is, compiler-generated. If you need to customize the record copy semantics, explicitly declare a copy constructor with the desired behavior.
protected WithOperatorTest(WithOperatorTest original)
{
// Logic to copy reference types with new reference
}
And in terms of what benefits it gives, I think it should be quite obvious now, that it makes copying of instances much easier and convenient.
Basically, the with operator will create a new object instance (records only, for now), by "coping values" from the "source" object and override some named properties in the destination object.
For example, instead of doing this:
var person = new Person("John", "Doe")
{
MiddleName = "Patrick"
};
var modifiedPerson = new Person(person.FirstName, person.LastName)
{
MiddleName = "William"
};
you can do this:
var modifiedPerson = person with
{
MiddleName = "Patrick"
};
Basically, you will write less code.
Use this source to get more details on the example above and official documentation for more examples.
Short answer is the following:
with keyword in C# was added for easier copy of complicated objects, with a possibility to override some of the public properties.
Examples are already briefly provided in the accepted answer.
Firstly, I am adding my class in list<>:
And then copying that class to new class and after changing date as per logic saving again in list<>, but date of first element already saved in the list is also being changed.
Look at the following image:
This is my complete code:
if (Session["CompanyId"] != null)
{
List<CalendarList> CalendartableList = new List<CalendarList>();
DateTime cldate = Convert.ToDateTime(CalendarList.DateDue);
CalendarList.CompanyId = Convert.ToInt32(Session["CompanyId"]);
CalendarList.Category = 15;
CalendarList.Status = 1;
CalendarList.Identifier = 232;
CalendarList.Quarter = 5;
CalendarList.IsCompleted = false;
CalendarList.CalendarGUID = CalendarList.Description;
CalendartableList.Add(CalendarList);
DateTime po_Date = cldate;
int pi_Count = 0;
while (po_Date.Year == DateTime.Now.Year)
{
pi_Count += 1;
switch (CalendarList.Interval)
{
case "Weekly":
{
po_Date = cldate.AddDays(7 * pi_Count);
break;
}
case "Biweekly":
{
po_Date = cldate.AddDays(14 * pi_Count);
break;
}
case "Monthly":
{
po_Date = cldate.AddMonths(1 * pi_Count);
break;
}
default:
{
po_Date = cldate.AddMonths(3 * pi_Count);
break;
}
}
if (po_Date.Year == DateTime.Now.Year)
{
CalendarList newlist = new CalendarList();
newlist = CalendarList;
newlist.DateDue = po_Date.ToString();
CalendartableList.Add(newlist);
}
}
Is there any other way to achieve the same?
What you need to remember is that you are adding a reference to your object, not a copy of that object, to the list. The simplest fix is to add a .Clone() method to your object to take a copy of it's self and create that as a new object. The cloned copy can be modified independent of the original.
Is CalendarList a class (maybe you show this in one of your images, but I can't see them)? If so, then it is a Reference Type.
There are two kinds of types in C#: reference types and value types. Variables of reference types store references to their data (objects), while variables of value types directly contain their data. With reference types, two variables can reference the same object; therefore, operations on one variable can affect the object referenced by the other variable. With value types, each variable has its own copy of the data, and it is not possible for operations on one variable to affect the other (except in the case of in, ref and out parameter variables; see in, ref and out parameter modifier).
So, when you call newlist = CalendarList you're not copying the values from CalendarList to newlist, you're setting newlist to refer to the exact same object as CalendarList. When you modify the object through the newlist variable, you will "see" those modifications through the CalendarList variable since they both reference the same object.
If you want two different objects, you'll have to manually copy the values from CalendarList to newlist.
CalendarList newlist = new CalendarList
{
CompanyId = CalendarList.CompanyId,
Category = CalendarList.Category
//etc, etc...
}
Note that you will encounter similar behavior if the properties of the CalendarList class are also reference types. In my example above, newlist.Category references the exact same object as CalendarList.Category. So, modifications to Category through newlist will be visible in CalendarList.Category.
I create 3 objects but when I change one object property among 3 object all of it is changed too.
so how can I change object property without effect other objects?
public DetachForm(MessageViewModel messageViewModel)
{
a = new MessageViewModel();
a = messageViewModel;
var b = new MessageModel();
b = a.CurrentMessage;
//property name in messageViewModel,a and b object equal to "Old"
b.Name = "New";
//property name in messageViewModel,a and b object equal to "New"
}
I think you should look closely at what is actually going on.
public DetachForm(MessageViewModel messageViewModel) // <--- first object in memory
{
a = new MessageViewModel(); // <--- create a new object in memory
a = messageViewModel; // <--- change the reference a to reference the messageViewModel
var b = new MessageViewModel(); // <--- create a new third object in memory
b = a; // <--- change b to reference the same object as a
a.id=1; // At this point messageViewModel, a, b - all reference the same object in memory
}
Therefore when you get to the line of a.id = 1 you actually change the one object in memory that all of these three references are referencing.
Also once you execute the second line of the function then the object you just created has no reference referencing it and the GC will collect that memory. Same applies to forth line of function.
To change a property of b without changing messageViewMovel (as these are reference types and in any case you are creating a new instance):
var b = new MessageViewModel();
b.id = 1; // when debugging see that messageViewModel was not changed
Even in your update you have the same problems. The following code is equivalent to what you wrote in your update:
a = messageViewModel;
var b = a.CurrentMessage;
b.Name = "New";
So as you see it doesn't matter you created new instances if then you override them with the "old" one. So when you change b.Name you actually access the same object in memory as a.CurrentMessage.Name.
If you want to duplicate all the MessageViewModel then I recommend having a look at IClonable (or have copy constructors). If your class will implement the interface then you can:
var copy = messageViewModel.Clone();
copy.CurrentMessage.Name = "something"; // original will not change
This behaviour comes from the way C# handles your object references. When you do:
b = a;
You say that b should reference the same object as a. You are modifying the same object, no matter if you use the a or b reference.
Currently I am receiving an array of objects from a database.
object [] sqlResultData = DatabaseCall.Result();
This array of objects needs to be matched to class variables like this
CClassOfVars classVar = new CClassOfVars();
classVar.myProperty = sqlResultData[0];
classVar.myProperty1 = sqlResultData[1];
What i wish to do is pass the list of propertys on the class in order to a function and have the mapping from the object array occur automatically based on the order.
For example:
Method defined like this
FillData(object [] databaseValues, IList<object>())
Called like this
CClassOfVars classVar = new CClassOfVars();
object [] sqlResultData = DatabaseCall.Result();
FillData(sqlResultData, new List<object>(){classVar.myProperty,classVar.myProperty1});
The FillData function would hopefully type cast and set the values of myProperty and myProperty1 to the values in array locations of 0,1 etc...
Something like this
FillData(object [] databaseValues, IList<object> mapMe)
{
for (int i = 0; i < mapMe.Count; i++)
{
mapMe[i] = CastToTheCorrectType(mapMe[i], databaseValues[i]);
}
}
Cast to the correct type could look like this?? I took from here: cast object with a Type variable
public T CastToTheCorrectType<T>(T hackToInferNeededType, object givenObject) where T : class
{
return givenObject as T;
}
How can i pass a list of different object types to all have there values modified and assigned within a different function?
The matter you asking about is dark and difficult to be implemented through just a function. There are frameworks out there dealing with object relational mapping. If it is an option, install and learn some OR/M. If not ... well, there might be some dirty way.
You can use the JSON.NET library to do the heavy lifting for you. It's super easy to use and install through Nuget. My point is as follows.
Construct an anonymous object. Use the property names of the original object.
Fill it with the data from the object array. Spin a loop over the object array...
Serialize the anonymous object.
Deserialize the JSON string into the target type.
At this point, JSON.NET will handle property mapping for you.
List item
E.g. if your target type is Person you might do this:
var x = new
{
FirstName = String.Empty,
LastName = String.Empty
};
var persons = new List<Person>(sqlResultData.Length);
foreach (var record in sqlResultData)
{
x.FirstName = record[0];
x.LastName = record[1];
var s = JsonConvert.SerializeObject(x)`
var personX = JsonConvert.Deserialize<Person>(s);
persons.Add(person);
}
I have an instance of a class that is about to be nulled out (objA = null). Before that happens I want to copy the fields of that object into another instance that I will save (objB).
If I do the following will objB keep its values after objA is null.
objB.field1 = objA.field1;
objB.field2 = objA.field2;
objB.innerClass = objA.innerClass;
Then later...
objA = null;
What if one of the fields is a reference type instead of a value type? Will that make a difference?
This can be easily tested. I have an example (SomeProp is an int?):
private int? Q = 5;
private void button_Click(object sender, RoutedEventArgs e)
{
MyClass a = new MyClass();
a.SomeProp = Q;
MyClass b = new MyClass();
b.SomeProp = a.SomeProp;
a = null;
MessageBox.Show( b.SomeProp.ToString() ); //Outputs 5
Q = null;
MessageBox.Show( b.SomeProp.ToString() ); //Still outputs 5
}
I tried exactly the same code but using string, no difference in output.
Primitives (Value Types) will have memory allocated.
A Reference type will have an address in memory. When you assign another Reference type a value from another object, that value will just point to the address in memory.
After setting an Reference type to null, any pointer to that address will return null.
A good explanation can be found here:
Primitive Types and Reference Types