Using lists of custom classes - c#

I've recently run into a snag in my program where using a list of a user defined class has been corrupting data. Example:
class myClass {
public int x;
}
myList<myClass> = new List<myClass>();
myClass myObject = new myClass();
myList.Add(myObject);
myList.Remove(myObject);
When I try to add something to the list, my data is being corrupted. I believe removing objects is also causing problems, although this could be because they're corrupted in the first place. I've seen similar issues here and there and was hoping someone could explain to me what's going on. While the links do provide me with some answers, they're not doing a good job of explaining what's going on behind the scenes.
EDIT: I should have been more clear before about how my data is being corrupted. The values in the fields of my objects are being changed when they are added to the list. For the purposes of my program, the values should all be 0 or 1 but when added to the list change to -1 to 3.
EDIT 2: The source of the problem was an unfamiliarity with C#. Coming from a C++ background I assumed that objects were passed by value and not by reference. Changing my custom class from a class to a struct resolved the issue instantly. Thanks to #MattW !

There isn't too much to go on here - so the following is a guess at the problem ...
Are you changing the value of myObject after adding it to the List<>? Remember that since you are adding a Class to the list (and all Classes are Reference types), that if you change the value of myObject after adding it to the list, it will be changed everywhere (including inside of your List<>).
For example:
List<myClass> myList = new List<myClass>();
myClass myObject = new myClass();
myObject.x = 5;
myList.Add(myObject);
Console.WriteLine(myList[0].x); //this will be 5
myObject.x = 7;
Console.WriteLine(myList[0].x); //this will be 7
Even though you didn't touch the List<> itself, you changed the value of the Referenced object, so it is changed everywhere it is being Referenced.
Check Out Value vs Reference types

Related

in c#, Why this code work as by reference? I intended to use as by value

I'm trying to make a list of class as history.
So list of a class was declared like this.
private List<SearchHistoryItem> SearchHistoryList;
SearchHistoryItem is a class that have two property.
public DataTable SearchResultDataTable;
public SearchCondition SearchCondition; // this is another class.
Whenever this method is called, I make temporary 'SearchHistoryItem', copy from current instance and add to the list.
public void GetMainDataAsConditionMethod()
{
SearchHistoryItem tmpItem = new SearchHistoryItem();
tmpItem.SearchCondition = CurrentSearchCondition;
tmpItem.SearchResultDataTable = MainChartDataTable;
SearchHistoryList.Add(tmpItem);
}
I think there is no reason to copy datas by reference. But when this code is running,
every items in the List 'SearchHistoryList' have same values of CurrentSearchCondition and MainChartDataTable.
I checked
How can I solve this to be copied by value?
When you assign an object (such as a List) to a variable, you assign a reference. When you do anything to the object on one reference, all references will show the change, because they are just references to the same object.
What you want to do is copying the list before you pass it on, such as
tmpItem.SearchResultDataTable = new List<...>();
tmpItem.SearchResultDataTable.AddRange(MainChartDataTable);
Note: This only creates a shallow copy, not a deep copy. If you want a deep copy, would have to clone each object in the list individually.

Create a copy of an ObservableCollection that doesn't update

I am building a control in xamarin forms that binds to a list of objects. To get this binding to work I need to use observable collections (otherwise propertychanged methods don't fire).
I noticed a really frustrating interaction as a result of needing to use OC's as opposed to lists. Whenever the binded OC updates, the values in my controls are automatically updated, even if they are just references of the OC, Here is how i am copying the OC.
//Internal list of events
private List<EventItem> _events;
void OnEventsChanged(ObservableCollection<EventItem> eventsCollection)
{
//Error handle
List<EventItem> events = eventsCollection.ToList();
//Do something
_events = events;
}
The problem comes when the OC updates, I want to check for new/deleted AND altered objects. The issue is that when the OC updates, it is updating the internal list (_events) aswell. This means when I go to do comparisons between the old & new values, they are the same.
Honestly I don't really understand how c# handles copying references of objects around, I had a similar issue a while back with DateTime.Now being calculated as opposed to copying the value of the already initialised object.
var time = DateTime.Now;
await Task.Delay(1000);
var time2 = time; //This is 1 second later than time, not the value of time (which is what I wanted)
I have used Objective-C in the past and that has the concept of MutableCopy where you can assign a new list from an existing one, they have the same values but aren't linked.
How can I do this in C# so that my controls internal list is only updated by me and not the OC?
Thanks
That's perfectly normal. If I have enough time, I'll try to explain it to you.
In a nutshell, the observableList (or a List) is a list of reference to the objects and not a list of objects. The thing is that the objects are not copied inside a list but the list contains a reference to the different objects. That means that if you do something like ToList(), you get another list of references to the exact same objects.
Now to solve your problem. Just create a new list with new objects with something like
var newList = oldList.Select(x => new Model(x)).ToList();
And of course the Model class has a constructor that accept a Model as a parameter and copy the properties.
When you write _events = events;, you create not a new object, but a reference for the same object. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/index .
You should to clone (create a copy of object itself) as it mentioned in comment by #Matt.

C# Cast works only in debugger

I’m developing a mobile application which among other things, it receives data from medical devices via Bluetooth. To this end, I’m using an Android SDK in JAR via binding to my Xamarin project. Here’s the class that holds the returned data from the decompiled JAR:
package com.contec.jar.contec08a;
import java.util.ArrayList;
public class DeviceData
{
public ArrayList<byte[]> mData_blood = new ArrayList();
public ArrayList<byte[]> mData_oxygen = new ArrayList();
public ArrayList<byte[]> mData_normal_blood = new ArrayList();
}
What is of interest is the mData_blood. Each element of the array list corresponds to a patient. Each byte array is the medical data for each patient. The Xamarin framework makes some changes, i.e. the name of the property becomes MDataBlood.
Problem: when I receive the above class and property, the casting fails BUT NOT in the debugger. Here’s what I mean: the ‘as’ operator that implement the cast fails (returns null) but in the debugger the very same expression correctly shows the data.
What’s more, the ‘is’ operator returns false in runtime (the canDo variable is false) but true in the debugger. I’ve tried all methods of casting I’m familiar with, even using –but not mixing – Android objects. The highlighted line which casts the IList to List produces a nice exception. I’m at a total loss. Any suggestions would be greatly appreciated.
Here's the screenshot from the debugger which illustrates all the above:
Edit1: The MDataBlood[0] evaluates as generic Java object. When reviewing its properties, its isArray is set to true. By checking the decompiled source of the SDK, I determined that is indeed byte array.
In Xamarin, there are some castings that might fail when the objects come from java types. In that cases you should use JavaCast<TResult> instead of a regular casting.
Try this, instead of your current approach:
// Since MDataBlood is exposed as an IList property of MDeviceData,
// we first need to cast it to IJavaObject
var dataBloodRaw = (IJavaObject)dm.MDeviceData.MDataBlood;
// Then we have access to its JavaCast method
var dataBlood = dataBloodRaw.JavaCast<JavaList<byte[]>>();
JavaList<T> extends Java.Lang.Object, so it can be used as the TResult parameter for JavaCast<TResult>. Also, it implements IList, so you should be able to loop through it.
Anyway, if you need a List<byte[]> you can use the casted JavaList for creating it:
var dataBloodList = dataBlood.ToList();
Or, alternatively
var dataBloodList = new List<byte[]>(dataBlood);
Yet another thing you could just try is to Java-cast dataBloodRaw to a JavaList<object> and then loop through its objects, trying to cast each one of them as a byte[].
Plan B
If none of the above works, I suggest you to take a look at this answer where it is suggested to disable linking for Release, which can be done in your project properties:
Keep in mind that a side effect of this last option will be the impact on the final size of your application.

C# Code searching the assigned values

I am running into a strange problem with existing code in C# Windows application.
The architecture of the code is in such a way that a single collection contains multiple properties. This gets populated at various places all across various modules -
Just to explain lets say a property -
public Class MyCollection
{
public list<ClassA> classA {get ; set ;}
public list<ClassB> classB {get;set;}
--
--
--
-- this continues up to 20 more properties.
}
The instance of this collection is used either to retrieve the values of collections -
For example getting the values -
Public void Function(MyCollection x)
{
var m= x.ClassA; //Get;
x.ClassA= function to populate List of ClassA; ( Pseudo code)
}
The problem occurs in finding out all the places in code where this collection is populated. I tried with searching references but it gives me 1000 places where this instance has reference, so this is of no help.
Fortunately the name of instance x is same all across. Is there any way or macro which can let me check wherever collection of instance is assigned ?
x.ClassA= // - find everywhere. So i am trying to search a wildcard as
x.___=
Any input is deeply appreciated.

C# SQL CLR Project - Public Generic.List items show up as non-public members in debugger

I'm having an issue in a C# SQL CLR project where publicly declared Generic.List items are not showing up as public in the debugger. This is problematic because I'm trying to serialize the object to XML. The real project has some complex objects, but a very simple example would be something like this:
[Microsoft.SqlServer.Server.SqlProcedure]
public static void DoSomething()
{
// the Thing Object has a public property of List<string>
// that is created in the constructor
Thing t = new Thing();
t.Items.Add("test");
t.Items.Add("test2");
// now, if I look at t in the debugger, it has given the
// items list a capacity of 4 and shows the items as
// non-public members (2 with values and 2 that are null)
}
I wanted to post an image from the debugger here, but it appears I cannot do that as a new user...
With all of that said, is this behavior because it is a SQL CLR project? The same code worked fine when developing in a console application (though I guess I could have messed something up when adding it to the CLR project).
Adding additional detail on the Thing object - it includes the following declaration for the Items:
public List<string> Items { get; set; }
Then, in the debugger, the Items just shows Capacity and Count (no actual items or properties for the Items). The actual item instances are listed under Non-Public members.
The Items property itself can never be seen by a debugger, because it is an indexed property, so there isn't a value you can just get for it, and hence examining the value it returns doesn't make sense (like examining the 30th of February or a politician's kept promises; it just doesn't exist).
List<T> uses the DebuggerTypeProxyAttribute attribute to define another class to be used to give a debugger eye view. This class (one internal to mscorlib) has a public Items property that returns an array with a copy of the list's items, so that it looks like you can actually examine the Items property of List<T> when really you are examining the Items property of an object that copies out the items when invoked.
Debuggers don't have to use this approach, so maybe the one you are using doesn't, or there's some other restrictions, but if you are using a debugger that doesn't support DebuggerTypeProxy you can just examine the private member that stores the items in an array (the array will be at least as large as Count, and possibly a bit larger to leave growing room rather than resizing on each Add; you can ignore elements beyond Count - 1).
This has nothing to do with XML serialisation, so whatever problem you are having with that is likely completely unrelated.
Edit:
I see some people are having other problems with XML serialisation and the SQL CLR as per these:
SQL Server not finding serialization assembly
http://connect.microsoft.com/VisualStudio/feedback/details/753005/when-deploying-a-sqlclr-assembly-with-a-generated-xmlserializer-assembly-the-xmlserializer-assembly-should-be-deployed
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/3fa5dce3-b0f3-44f8-9b7b-65439f1c98ae/cannot-deploy-xmlserializers-clr-assemblies?forum=ssdt
http://social.msdn.microsoft.com/Forums/sqlserver/en-US/e6560fa4-76f1-4da2-b795-7926d0743baa/sql-clr-problem-with-xmlserializer?forum=sqlnetfx
Your XML problem is indeed different to your debugger view issue. (I meanwhile am off to add debugger proxies to some of my collection types, I've always figured people would just skip through to the inner members and not care, but you've made me rethink that one).

Categories

Resources