I'm writing a serializable object that contains a collection. So, in order to be able to add and remove items from that collection, I added methods that would first convert the collection from an Array into a List, add or remove the items and then convert the List back into a Array.
public void AddElement(Element element) {
List<Element> list = new List<Element>(this.elements);
list.Add(element);
this.elements = list.ToArray();
}
Is there maybe a problem creating the List like this?
List(this.elements)
Or is it a problem, that the Array is Length is 0 at start?
EDIT1: converting from a list field also leaves an empty array.
EDIT2: XML Serialization is not wanted.
Your code works fine. Here is the MCVE:
Program.cs
using System;
namespace Test1
{
class Program
{
static void Main(string[] args)
{
var test = new TestClass();
test.AddElement(new Element());
Console.WriteLine(test.HowMuch());
}
}
}
TestClass.cs
using System.Collections.Generic;
namespace Test1
{
class TestClass
{
private Element[] elements = new Element[0];
public void AddElement(Element element)
{
List<Element> list = new List<Element>(this.elements);
list.Add(element);
this.elements = list.ToArray();
}
public int HowMuch()
{
return elements.Length;
}
}
}
Element.cs
namespace Test1
{
class Element
{
}
}
The example outputs 1, not 0.
The most probable reason is that you assign this.elements to a variable, hence, store old version of the array.
Related
I am trying to add values in a dictionary having list of tuples but the key is same.
I am doing like this
public struct MyStruct { public List> list1; }
public static Dictionary<long, MyStruct> myDictionary = new
Dictionary<long, MyStruct>();
funct()
{
if (myDictionary.ContainsKey(key))
{
myDictionary[key]= new MyStruct { list1 = s.list1 };
} // this block is been called from another function
}
But as I am using new keyword every time the value coming is getting overwrite. but I want to append for which I am not getting another way. Please suggest me another way.. as I searched all over net but none solves my problem.
Instead of using new keyword everytime, you can check for null, then add values to the list inside of your structure:
funct(){
if (myDictionary.ContainsKey(key))
{
if(myDictionary[key].list1 != null)
myDictionary[key].list1.AddRange(s.list1);
else myDictionary[key].list1 = new MyStruct { list1 = s.list1 };
} // this block is been called from another function
}
This way if you already have values inside the list in the structure from the dictionary the new values will b added at the list too. If you do't have any value and the list is simply null, the program will act as by now and make a new list.
If you want to add a value to a Dictionary<TKey, TValue>, first you need to check if the key already exists because keys should be unique, if the key doesn't exist you can set a value, otherwise if the key already exists then you get the value using that key and update it. Check the below example I hope it will help you understand how it works. You can execute the below example here
//Rextester.Program.Main is the entry point for your code. Don't change it.
//Compiler version 4.0.30319.17929 for Microsoft (R) .NET Framework 4.5
using System;
using System.Collections.Generic;
namespace Rextester
{
public class Program
{
public static Dictionary<long, MyStruct> myDictionary = new Dictionary<long, MyStruct>();
public static void Main(string[] args)
{
myDictionary.Add(1, new MyStruct { Numbers = new List<int> { 1, 2} });
Add(1, 3);
// printing out the values
foreach(KeyValuePair<long, MyStruct> number in myDictionary)
{
Console.WriteLine("Key: {0}", number.Key);
Console.WriteLine("Values:");
for(var i = 0; i < number.Value.Numbers.Count; i++)
{
Console.WriteLine(number.Value.Numbers[i]);
}
}
}
public static void Add(long key, int number)
{
if (myDictionary.ContainsKey(key))
{
var myStruct = myDictionary[key];
if (myStruct.Numbers != null)
{
myStruct.Numbers.Add(number);
}
}
else
{
myDictionary[key] = new MyStruct { Numbers = new List<int> { number }};
}
}
}
public struct MyStruct
{
public List<int> Numbers;
}
}
I have a Model object that contains a list of node. These nodes contain a signature.
I would like to have a property with a getter returning an array of signatures. I have trouble to instantiate the array and I'm not sure if I should use an array/list/enumerable or something else.
How would you achieve this?
using System;
using System.Collections.Generic;
using System.Linq;
namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
var m = new Model();
Console.WriteLine(m.Signatures.ToString());
Console.ReadLine();
}
}
public class Model
{
public List<Node> Nodes { get; set; }
public int[][] Signatures
{
get
{
return Nodes.Select(x => x.Signature) as int[][];
}
}
public Model()
{
Nodes = new List<Node>();
Nodes.Add(new Node { Signature = new[] { 1,1,0,0,0 } });
Nodes.Add(new Node { Signature = new[] { 1,1,0,0,1 } });
}
}
public class Node
{
public int[] Signature { get; set; }
}
}
Use ToArray()
return Nodes.Select(x => x.Signature).ToArray();
And something like this to output it correctly:
Array.ForEach(m.Signatures, x=>Console.WriteLine(string.Join(",", x)));
In your Signatures property you try to use the as operator to convert the type into int[][]. The Select method however returns an IEnumerable<int[]> which is not an array. Use ToArray to create the array:
public int[][] Signatures
{
get
{
return Nodes.Select(x => x.Signature).ToArray();
}
}
Basically, I want to know if I can do this with two ObservableCollections:
oldList = newList;
I have two lists that get populated throughtout my app, and each time they get populated, I want the 'new' values to become the 'old' values, and then get a new set of values to put in the 'new' list.
is it that easy? Any other way to do this without iterating over the whole newList every time?
EDIT: This is how the new list is being populated. Basically, I just want the contents of the newList to be put into the oldList.
foreach (object obj in ts.GetVariables())
{
if ((obj.ToString() != "_SMSTSReserved2") || (obj.ToString() != "OSDJoinPassword") || (obj.ToString() != "OSDLocalAdminPassword"))
{
TSVar var = new TSVar();
var.TSVarName = obj.ToString();
var.TSVarValue = ts[obj.ToString()];
newList.Add(var);
}
}
oldList.Clear();
foreach (TSVar var in newList)
{
oldList.Add(var);
}
If you use the extension method listed below, what you are trying to do becomes a one liner:
oldList.Replace(newList);
I would create an Extension Method for ObservableCollection like this:
public static class ObservableCollectionExtensionMethods
{
public static void Replace<T>(this ObservableCollection<T> old, ObservableCollection<T> #new)
{
old.Clear();
foreach (var item in #new)
{
old.Add(item);
}
}
}
And this is how you would use it:
using System.Collections.ObjectModel;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace ExtensionMethods
{
[TestClass]
public class ObservableCollectionExtensionMethodsTest
{
[TestMethod]
public void ReplaceTest()
{
// Arrange
var old = new ObservableCollection<string> { "1"};
var #new = new ObservableCollection<string> {"2"};
// Act
old.Replace(#new);
// Assert
Assert.AreEqual("2", old.First());
}
}
}
I think this is what you may be looking for? This will add everything that was in newList to your oldList.
ObservableCollection<YourType> oldList = new ObservableCollection<YourType>(newList);
newList.clear();
//put new stuff in your list here.
I'm trying to add new values input by the user on a separate windows form into the following array:
public class NameValue
{
public string Name;
public string Value;
public NameValue() { Name = null; Value = null; }
public NameValue(string name, string value) { Name = name; Value = value; }
}
public class DefaultSettings
{
public static NameValue[] Sites = new NameValue[]
{
new NameValue("los angeles, CA", "http://losangeles.craigslist.org/"),
};
public static NameValue[] Categories = new NameValue[]
{
new NameValue("all for sale", "sss"),
};
}
How do I add the new values to the array while keeping the values of the old array?
Edit
I tried using Mr. Noren's function:
static void AddValueToSites(NameValue newValue)
{
int size = DefaultSettings.Sites.Length;
NameValue[] newSites = new NameValue[size + 1];
Array.Copy(DefaultSettings.Sites, newSites, size);
newSites[size] = newValue;
DefaultSettings.Sites = newSites;
}
private void button1_Click(object sender, EventArgs e)
{
NameValue newSite = new NameValue("Test, OR", "http://portland.craigslist.org/");
AddValueToSites(newSite);
Close();
}
But that's not working... The class I am getting data from is:
public partial class Location : Office2007Form
{
public Location()
{
InitializeComponent();
}
static void AddValueToSites(NameValue newValue)...
private void button1_Click(object sender, EventArgs e)...
}
You cannot change the size of an array, ever. You would need to use something like a List for that.
Since you're using name/value pairs you should consider using Dictionary<TKey,TValue>.
Finally, if you're looking to have different classes contribute to the contents of the arrays, then that's not going to happen.
You can't add to an array, whether it's in another class or not.
Use List<NameValue> instead of NameValue[] and then you can use Sites.Add(...).
If you're absolutely married to the idea of using an array versus some more flexible collection, you should implement some AddX() methods in the class that is defining the base values. Those methods would take care of inserting the new values in the array. If you're not concerned with multithreading issues, it can be very simple:
(Warning: code is from my head and not tested)
static void AddValueToSites(NameValue newValue)
{
int size = Sites.Length;
NameValue[] newSites = new NameValue[size+1];
Array.Copy(Sites, newSites, size);
newSites[size] = newValue;
Sites = newSites;
}
And again for Categories.
Like others suggested, using List<NameValue> or Dictionary<string,string> would be options that would be more fluid. These already have Add, Remove, Contains, etc. - basically all you need when you need to manipulate arrays.
Arrays are not mutable in place, so if you resize them (using any approach) it'll result in a different instance being created (this is what happens in VB.NET's ReDim but they hide it from you).
The simplest way to resize an array in C# is to use the Concat extension method (requires System.Linq):
string[] myArray = new string[] { "Hello", "World" };
myArray = myArray.Concat(new string[] { "Something", "new" };
myArray will now be 4 elements deep. I don't think this will work between classes though (haven't tried though).
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.