I know this is asked many times and i am trying to implement same . I have list below
internal class GenList
{
public string Col1 { set; get; }
public string Col2 { set; get; }
}
List<GenList> MainList = new List<GenList>();
I want to copy list into other list and dont want content to change in cloned list if something is changed in main list. So i am trying to do below
List<GenList> cloned = MainList.ConvertAll(GenList => new GenList {});
I dont know what to enter inside those curly braces in above line.
dont want content to change in cloned list if something is changed in main list.
That sounds like you want a deep clone, basically. In other words, creating a new list where each element is a copy of an element in the original list, not just a reference to the same object as the original list refers to.
In your case, that's as simple as:
var cloned = MainList.ConvertAll(x => new GenList { Col1 = x.Col1, Col2 = x.Col2 });
Or with LINQ:
var cloned = MainList.Select(x => new GenList { Col1 = x.Col1, Col2 = x.Col2 })
.ToList();
But note that:
If you add a new property, you will need to change this code
If you add a property of a mutable type, you'd need to clone that too
Options to consider:
Adding a DeepClone() method to GenList, to keep the logic in one place however many places need it.
Adding a constructor instead: GenList(GenList) which copies appropriately
Using immutable types instead (e.g. make GenList immutable) at which point shallow clones of collections are sufficient.
Here is a quick deep clone solution via serialization:
[Serializable]
public class GenList
{
public string Col1 { set; get; }
public string Col2 { set; get; }
public GenList DeepClone()
{
using (var stream = new MemoryStream())
{
var formatter = new BinaryFormatter();
formatter.Serialize(stream, this);
stream.Position = 0; //reset stream
var cloned = formatter.Deserialize(stream) as GenList;
return cloned;
}
}
and a test to verify:
[TestClass]
public class DeepCloneTests
{
[TestMethod]
public void ReferencesAreNotMaintained()
{
var object1 = new GenList() { Col1 = "a", Col2 = "b" };
var cloned = object1.DeepClone();
Assert.AreEqual(object1.Col1, cloned.Col1);
Assert.AreEqual(object1.Col2, cloned.Col2);
cloned.Col1 = "c";
cloned.Col2 = "d";
Assert.AreNotEqual(object1.Col1, cloned.Col1);
Assert.AreNotEqual(object1.Col2, cloned.Col2);
}
}
Related
Here I've selected the record which a want to get into a new variable. and after that, when I'm changing the value of 'itm.note' it's automatically modifying the original list (Obj.Testlist) as well. How can this be avoided? Only want to change 'itm' object and Obj.Testlist list should be keep as it is.
var itm = Obj.Testlist.Where(x => x.id == 1).SingleOrDefault();
itm.note = "text";
You could clone the fetched item, but that wouldn't be efficient.
How about this:
var changedFetchedItem = Obj.Testlist.Where(x => x.id == 1)
.Select(x => new
{
Id = 1,
Note = "text",
// copy the other properties that you plan to use
// don't copy the ones that you don't use.
}
.SingleOrDefault();
Since you will be fetching at utmost one item, this is very efficient.
I chose to create an object with anonymous type. If you need a specific type, you can add the type after the keyword new
Since I have large model, decided to use cloning for this (Sample code),
public class TestClone : ICloneable
{
public bool IsSuccess { get; set; }
public string Note { get; set; }
public string ErrorDetail { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
static void Main(string[] args)
{
var test1 = new TestClone() { IsSuccess = true, Note= "text", ErrorDetail = "DTL1" };
var test2 = (TestClone) test1.Clone();
test2.Note= "new text";
}
If you have made a list of Custom objects is it a must to have to do with Hashcodes if you wanna check that list to see if it contains a object before adding it, I mean so that you do not get duplicates in the list or is there an easier way basically I want to use the contains method on a custom object list to see if the object I want to add already exists in the list and if there then is an easier way then to have to deal with hashcodes?
This is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataConverter.Objects;
namespace DataConverter.Converters
{
class CategoryConverter
{
private Category category;
private SubCategory subCategory;
private ExcellObj excellObj;
public CategoryConverter(string path)
{
excellObj = new ExcellObj(path);
}
public List<Category> getCategoryListExcel()
{
List<Category> categories = new List<Category>();
List<string> ColumnNames = new List<string> { "Group1", "Group1Descr" };
List<int> CorrectColumn = new List<int>();
for(int i = 0; i < ColumnNames.Count; i++)
{
CorrectColumn.Add(excellObj.findColumn(ColumnNames[i]));
}
for(int i = 2; i < excellObj.allRows; i++)
{
categories.Add(category = new Category(excellObj.getValuesFromCell(i, CorrectColumn[1]), excellObj.getValuesFromCell(i, CorrectColumn[0]), "Home"));
}
return categories;
}
public List<List<SubCategory>> getSubCategory()
{
List<SubCategory> subCategories1 = new List<SubCategory>();
List<SubCategory> subCategories2 = new List<SubCategory>();
List<List<SubCategory>> subCategoriesList = new List<List<SubCategory>>();
List<string> ColumnNamesSubCategory1 = new List<string> { "Group2", "Group2Descr" };
List<string> ColumnNamesSubCategory2 = new List<string> { "Group3", "Group3Desc" };
List<int> CorrectColumn1 = new List<int>();
List<int> CorrectColumn2 = new List<int>();
for(int i = 0; i < ColumnNamesSubCategory1.Count; i++)
{
CorrectColumn1.Add(excellObj.findColumn(ColumnNamesSubCategory1[i]));
CorrectColumn2.Add(excellObj.findColumn(ColumnNamesSubCategory2[i]));
}
for(int i = 1; i < excellObj.allRows; i++)
{
subCategories1.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i, CorrectColumn1[1]),excellObj.getValuesFromCell(i,CorrectColumn1[0]), "Home"));
subCategories2.Add(subCategory = new SubCategory(excellObj.getValuesFromCell(i,CorrectColumn2[1]), excellObj.getValuesFromCell(i,CorrectColumn2[0]), "Home"));
}
subCategoriesList.Add(subCategories1);
subCategoriesList.Add(subCategories2);
return subCategoriesList;
}
public void finnishedUsingExcel()
{
excellObj.CloseApplication();
}
}
}
and what i whant to happen is that i whant to run a
if(categories.Contains(category) == false){
categories.add(category)
}
i do not understand this part in the documentation?
public Person(string lastName, string ssn)
{
if (Regex.IsMatch(ssn, #"\d{9}"))
uniqueSsn = $"{ssn.Substring(0, 3)}-{ssn.Substring(3, 2)}-{ssn.Substring(5, 4)}";
else if (Regex.IsMatch(ssn, #"\d{3}-\d{2}-\d{4}"))
uniqueSsn = ssn;
else
throw new FormatException("The social security number has an invalid format.");
this.LastName = lastName;
}
Assuming you have a code like this:
List<CustomObject> listOfCustomObjects = new List<CustomObject>();
Solution 1
If so, you can use listOfCustomObjects.Contains(customObject) to find out if customObject is in listOfCustomObjects. You should add using System.Linq; to the top of your code in order to use this method.
Solution 2
Another way to not have duplicates in your list is basically not using a List. You can use HashSet instead. With this method, duplicate objects won't be added to your list automatically. HashSet is also in LINQ Library, so you should add the line using System.Linq; for this solution too. Here's an example how to create a new HashSet with your CustomObject class:
HashSet<CustomObject> setOfCustomObjects = new HashSet<CustomObject>();
You really should have your class implement IEquatable if it's reasonable to do so and you're going to check for equality with any frequency, just so it does not bite you. The "Contains" method will work, but only to test that the exact same instance is present, not necessarily one that just shares matching properties. Consider the following code:
class Program
{
static void Main(string[] args)
{
var classInstance = new MySampleClass("testA", "testB");
var classList = new List<MySampleClass>();
classList.Add(classInstance);
if (classList.Contains(new MySampleClass("testA", "testB")))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
if (classList.Contains(classInstance))
{
Console.WriteLine("true");
}
else
{
Console.WriteLine("false");
}
}
}
public class MySampleClass
{
public string SampleProperty1 { get; set; }
public string SampleProperty2 { get; set; }
public MySampleClass(string sampleProperty1, string sampleProperty2)
{
SampleProperty1 = sampleProperty1;
SampleProperty2 = sampleProperty2;
}
}
Even though we're checking for the presence of the class that has the exact same values as the one we previously added, they're still separate instances and you'll end up with duplicates in your list.
An alternative in the very limited case would be to use a LINQ method to check whether the list already contains an entry with a property that can be compared, such as an int ID or something:
yourList.Any(item => item.Id.Equals(otherItem.Id));
Again, if it's more than a one off, implement it the right way with IEquatable. See Microsoft's documentation
I am trying to serialize nested objects using reflection. I am able to do this fine for properties containing a single value, but I am having trouble with list type properties that contain another class.
In the code sample below I have a class Dish which contains a list of of Recipe classes as a property, which itself contains a list of Step classes.
I am able to get the PropertyInfo of the List property, but when I try to get the contents of it by invoking the get method, I get a simple object back, not a List of e.g. Steps:
var listObjects = property.GetGetMethod().Invoke(dish, null);
I managed to cast that into a List of objects like this:
List<object> listValues = ( listObjects as IEnumerable<object>).Cast<object>().ToList();
Now at least I can iterate over this List, but I cannot get the acutal properties of the original classes like the step description.
So I know the type of the List via property.PropertyType.GenericTypeArguments.First(), but its at runtime. I am thinking on how to perform a proper cast to transform my List<object> into a conrete type like List<Step>.
What I want to achieve: Serialize all property values of dish and all its attached Lists of objects.
I appreciate any ideas.
using System;
using System.Linq;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var dish = new Dish(){
Recipes = new List<Recipe>(){
new Recipe(){
RecipeName = "Preparation",
Steps = new List<Step>(){
new Step(){
Description = "Prepare Stuff",
}
}
},
new Recipe(){
RecipeName = "Main Course",
Steps = new List<Step>(){
new Step(){
Description = "Do this",
},
new Step(){
Description = "Then do that",
}
}
}, }, };
var serializer = new Serializer();
serializer.SerializeDish(dish);
}
}
public class Serializer
{
public void SerializeDish(Dish dish)
{
var dishType = typeof (Dish);
var listProps = dishType.GetProperties().Where(x => (x.PropertyType.IsGenericType && x.PropertyType.GetGenericTypeDefinition() == typeof (List<>)));
foreach (var property in listProps)
{
var propertyGetMethod = property.GetGetMethod();
var listObjects = propertyGetMethod.Invoke(dish, null);
Console.WriteLine("Name:"+property.Name + " " + "List-Type:"+property.PropertyType.GenericTypeArguments.First());
//Here its getting fuzzy
List<object> listValues = ( listObjects as IEnumerable<object>).Cast<object>().ToList();
foreach ( var item in listValues ) {
Console.WriteLine(item);
}
}
}
}
public class Dish
{
public List<Recipe> Recipes {get;set;}
}
public class Recipe
{
public string RecipeName{get;set;}
public List<Step> Steps {get;set;}
}
public class Step
{
public string Description {get;set;}
}
I'm doing something wrong because after the loop executed myData still contains objects with blank ids. Why isn't the myData object being updated in the following foreach loop, and how do I fix it?
I thought it could be that I wasn't passing the object by reference, but added a ref keyword and also moved to the main method and I'm still showing the object not being updated.
Additional Information
The user object in the foreach loop is being updated, but the myData list does not reflect the updates I see being applied to the user object.
** Solution **
I was not creating a List but an Enumerable which was pulling the json each time I went through myData in a foreach list. Adding a ToList() fixed my issue.
public class MyData
{
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
int index = 0;
// Does not allow me to up, creates an IEnumerable
//IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
// .Select(x => new MyData()
// {
// ID = x["id"].ToString(),
// Properties = x.OfType<JProperty>()
// .ToDictionary(y => y.Name, y => y.Value.ToString())
// });
//Works allows me to update the resulting list.
IEnumerable<MyData> myData = JObject.Parse(json)["Users"]
.Select(x => new MyData()
{
ID = x["id"].ToString(),
Properties = x.OfType<JProperty>()
.ToDictionary(y => y.Name, y => y.Value.ToString())
}).ToList();
foreach (var user in myData) // Also tried myData.ToList()
{
if (string.IsNullOrEmpty(user.ID))
{
user.ID = index.ToString();
user.Properties["id"] = index.ToString();
}
index++;
}
public class MyData
{
public MyData()
{
this.Properties = new Dictionary<string,string>();
}
public string ID { get; set; }
public Dictionary<string, string> Properties { get; set; }
}
public static void Main(string[] args)
{
IEnumerable<MyData> myDataList = new List<MyData>();
int index = 0; // Assuming your starting point is 0
foreach (var obj in myDataList)
{
if (obj != null && string.IsNullOrEmpty(obj.ID))
{
obj.ID = index.ToString();
// Checks if the Properties dictionary has the key "id"
if (obj.Properties.ContainsKey("id"))
{
// If it does, then update it
obj.Properties["id"] = obj.ID;
}
else
{
// Else add it to the dictionary
obj.Properties.Add("id", obj.ID);
}
}
index++;
}
I believe the reason why your objects are not updating because it's probably still referring to the memory block before your objects were changed. Perhaps. The easiest way (that I can think of, there are thousands of smarter programmers than me) is to create a new list and have it contain all of your updated objects.
Edit
I updated the code above with the code that I have. I created a method to set a small amount of objects to test:
private static IEnumerable<MyData> GetMyData()
{
return new List<MyData>()
{
new MyData(),
new MyData() {ID = "2"},
new MyData() {ID = "3"},
new MyData()
};
}
I was able to view my changes and then go through a foreach loop to view my changes. If the ID of the object is Null or Empty, then it steps into the if check and adds the current index to the ID as you know.
Now for my question: Which "id" is blank? The "id" in the dictionary or is it the ID of the model? Are all of your (Model).ID blank? As the updated code of yours, if your dictionary doesn't have "id" as a key, it's going to throw an exception saying it doesn't exist so you will need to do a check to make sure it does exist or add it if it doesn't.
I have in a SearchFlyClass an Arraylist GetFly()
...
public ArrayList GetFly(int tip, string country)
{
...
var list = new ArrayList();
var reader = command.ExecuteReader();
if (reader.HasRows)
{
...
while (reader.Read())
{
decimal nr_zbor = reader.GetDecimal(cod_zbor);
string aeroport = reader.GetString(nume_aeroport);
string companie = reader.GetString(nume_companie);
list.Add(nr_zbor);
list.Add(companie);
list.Add(aeroport);
}
}
...
and I wish to put in Form1.cs the list in listview by columns[zbor(colZbor),airport(colAirport),company(colCompany)], but I don't now how
private SearchFlyClass searchFly = new SearchFlyClass();
private ArrayList fly = new ArrayList();
...
private void ShowResultFlySearch(int direction, string country)
{
fly = searchFly.GetFly(direction, country);
for (int count = 0; count < fly.Count; count++)
{
string zbor = fly[0].ToString();
string companie = fly[1].ToString();
string aeroport = fly[2].ToString();
ListViewItem searchlist = new ListViewItem();
searchlist.Items.Add(new ListViewItem(elem));
}
}
can someone help me, please?
First you have to put ListView to View mode details, which you do with following code (it is also possible with setting View property in designer):
ListView listView = new ListView();
listView.View = View.Details;
Then you have to assign columns to the listView (can also be done in designer):
listView.Columns.Add("zbor");
listView.Columns.Add("airport");
listView.Columns.Add("company");
After this you have to assign other columns to ListViewItem subitems, by modifying your function:
private void ShowResultFlySearch(int direction, string country)
{
fly = searchFly.GetFly(direction, country);
for (int count = 0; count < fly.Count; count++)
{
string zbor = fly[0].ToString();
string companie = fly[1].ToString();
string aeroport = fly[2].ToString();
ListViewItem listViewItem = new ListViewItem(zbor);
listViewItem.SubItems.Add(airport);
listViewItem.SubItems.Add(companie);
listView.Items.Add (listViewItem);
}
}
The function assumes that it is in Form1.cs and that you have listView variable instantized as class variable of type ListView. Basics of C# and object oriented programming.
There are lots of issues with this code. Firstly, is there any reason that you're using ArrayList instead of the generic collection types? E.g. List<T>
Secondly, I would create a type to store all of the related data for one instance of your entity, rather than putting the column values for the entity into an untyped collection.
Thirdly, your aren't referencing count anywhere in your for loop - presumably because the query is returning a single entity, and therefore the for loop is redundant because you know the number of items returned for a single entity. You are also using a variable elem which doesn't seem to have been defined.
Updated
Define a type that describes your entity:
public class Flight
{
public decimal Code { get; set; }
public string Company { get; set; }
public string Airport { get; set; }
}
Change your method to return an instance of your entity:
public Flight GetFlight(int tip, string country)
Create a new instance to return from the method and populate it from your database query result:
var flight = new Flight();
flight.Code = reader.GetDecimal(cod_zbor);
flight.Airport = reader.GetString(nume_aeroport);
flight.Company = reader.GetString(nume_companie);
return flight;
Now your other method can use the updated method:
var flight = searchFly.GetFlight(...);
// access flight properties here
This assumes that your query returns a single entity. If it returns a collection, then you can use List<Flight> or IEnumerable<Flight> as your return type as appropriate.