I am trying to copy the list of items from list1 to another list list2. I'm able to do that. However I don't want the changes made in list2 tobe reflected in list1.
class Program
{
static void Main(string[] args)
{
List<MyClass> list1 = new List<MyClass>();
list1.Add(new MyClass(){ID = 1, Name = "name1"});
list1.Add(new MyClass(){ID = 2, Name = "name2"});
list1.Add(new MyClass(){ID = 3, Name = "name3"});
//Copy items from list1 to list2
List<MyClass> list2 = new List<MyClass>(list1);
list1.ForEach(x => Console.WriteLine(x.Name)); //It shows the name as added
//Empty items in list2
list2.ForEach(x => x.Name = string.Empty);
//Print items in list1
list1.ForEach(x => Console.WriteLine(x.Name)); //It shows the name is empty
Console.ReadKey();
}
}
class MyClass
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
I hope there should be an easy way.
Since this is a reference type you are changing all. You need to create a copy of that instance:
public class MyClass
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
public MyClass Copy()
{
return new MyClass
{
ID = this.ID,
Name = this.Name
};
}
}
Now you can create the second list in this way:
List<MyClass> list2 = new List<MyClass>(list1.Select(x => x.Copy()));
Of course you don't need that method. You could do that also on-the-fly in the LINQ query:
List<MyClass> list2 = new List<MyClass>(list1.Select(x => new MyClass { ID = x.ID, Name = x.Name }));
Another similar approach is a copy-constructor. A copy-constructor is used to initialize an instance by providing another instance of the same type:
public class MyClass
{
private int id;
public MyClass(MyClass instance)
{
this.id = instance.ID;
this.name = instance.Name;
}
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
Now you could fill the list with copies in this way:
List<MyClass> list2 = new List<MyClass>(list1.Select(x => new MyClass(x)));
or with List.ConvertAll:
List<MyClass> list2 = list1.ConvertAll(x => new MyClass(x));
If you want to use this feature in other places too, I guess the best way to do is, to create an extention method for IList like this:
static class Extensions
{
public static IList<T> Clone<T>(this IList<T> sourceList)
where T: ICloneable
{
return sourceList.Select(item => (T)item.Clone()).ToList();
}
}
And to use it, you should change your class and make it ICloneable:
class MyList : ICloneable
{
public MyList(int idParam, string nameParam)
{
ID = idParam;
Name = nameParam;
}
public object Clone()
{
return new MyList(ID, Name);
}
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
If your elements are reference types and type implement ICloneable interface you clould do something like this:
list1.ForEach((item) =>
{
list2.Add((ICloneable)item.Clone());
});
If your element type doesn't implement ICloneable, you clould create "copy" constructor and do something like this:
list1.ForEach((item)=>
{
list2.Add(new MyList(item.ID, item.Name));
});
Related
I'm having problems trying to get Should().BeEquivalentTo() to work with types that derive from a base class and implement a collection interface:
public class Entity
{
public string Id {get; set;}
public string Name {get; set;}
}
public class Derived : Entity, ICollection<Entity>
{
private List<Entity> m_Children = new List<Entity>();
public string Description { get; set; }
public int Count => ((ICollection<Entity>)m_Children).Count;
public bool IsReadOnly => ((ICollection<Entity>)m_Children).IsReadOnly;
public void Add(Entity item)
{
((ICollection<Entity>)m_Children).Add(item);
}
public void Clear()
{
((ICollection<Entity>)m_Children).Clear();
}
public bool Contains(Entity item)
{
return ((ICollection<Entity>)m_Children).Contains(item);
}
public void CopyTo(Entity[] array, int arrayIndex)
{
((ICollection<Entity>)m_Children).CopyTo(array, arrayIndex);
}
public IEnumerator<Entity> GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
public bool Remove(Entity item)
{
return ((ICollection<Entity>)m_Children).Remove(item);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((ICollection<Entity>)m_Children).GetEnumerator();
}
}
The Test
[TestMethod]
public void EquivalenceTest()
{
var expected = new Derived
{
Id = "123",
Name = "abc",
Description = "def"
};
var actual = new Derived
{
Id = "121",
Name = "xyz",
Description = "def"
};
actual.Should().BeEquivalentTo(expected); // This succeeds, but should fail
}
The call to BeEquivalentTo seems to be ignoring the properties that are defined in the object, and only treating the object as a collection.
How can I get the framework to check the properties and the contents of the collection?
Edit
It seems like this is a known issue
Does anyone know of a workaround?
It's a known issue when comparing classes that implements IEnumerable and have extra properties to be compared.
Here's a way to hack the comparison.
public class Entity : IEnumerable<int>
{
private int[] ints = new[] { 1 };
public int Id { get; set; }
public string Name { get; set; }
public IEnumerator<int> GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable<int>)ints).GetEnumerator();
}
[TestMethod]
public void EquivalenceTest()
{
var expected = new Entity
{
Id = 1,
Name = "abc",
};
var actual = new Entity
{
Id = 1,
Name = "abc",
};
actual.Should().BeEquivalentTo(expected, opt => opt
.Using<Entity>(e =>
e.Subject.Should().Match<Entity>(f => f.Name == e.Expectation.Name)
.And.Subject.Should().Match<Entity>(f => f.Id == e.Expectation.Id)
.And.Subject.Should().BeEquivalentTo(e.Expectation)
)
.WhenTypeIs<Entity>());
}
I have following object structure where B is derived from A and I am getting input as List<A> with lots of records. I want to convert thatList<A> to List<B> with easy steps (without looping). What is the best way to achieve the same.
Note: I don't want to use AutoMapper.
public class A
{
public A() { }
public virtual string Name
{
get;
set;
}
}
public class B : A
{
public B()
: base()
{
}
private string _name;
public override string Name
{
get
{
return _name;
}
set
{
_name = string.Concat("Hello ", base.Name);
}
}
public string Id
{
get { return "101"; }
}
}
You can do this by declaring constructor for class B from class A
in this way:
public B(A a):base()
{
this._name = a.Name;
}
And than do this:
var listA = new List<A> { new A { Name = "John" }, new A { Name = "Peter" }, new A { Name = "Julia" } };
List<B> listB = listA.Select(x=> new B(x)).ToList();
Based on the comments this is the output, though I still don't really understand the point.
List<A> thisIsA = new List<A>();
thisIsA.Add(new B());
List<B> thisIsB = new List<B>();
thisIsB.AddRange(thisIsA.Cast<B>());
I am trying to add entries in dictionary array list but i don't know which arguments to set in the People Class in the main function.
public class People : DictionaryBase
{
public void Add(Person newPerson)
{
Dictionary.Add(newPerson.Name, newPerson);
}
public void Remove(string name)
{
Dictionary.Remove(name);
}
public Person this[string name]
{
get
{
return (Person)Dictionary[name];
}
set
{
Dictionary[name] = value;
}
}
}
public class Person
{
private string name;
private int age;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
}
using this seem to give me error
static void Main(string[] args)
{
People peop = new People();
peop.Add("Josh", new Person("Josh"));
}
Error 2 No overload for method 'Add' takes 2 arguments
This peop.Add("Josh", new Person("Josh"));
should be this
var josh = new Person() // parameterless constructor.
{
Name = "Josh" //Setter for name.
};
peop.Add(josh);//adds person to dictionary.
The class People has the method Add which only takes one argument: a Person object. The Add on the people class method will take care of adding the it to the dictionary for you and supplying both the name (string) argument and the Person argument.
Your Person class only has a parameterless constructor, which means that you need to set your Name in the setter. You can do this when you instantiate the object like above.
For your design this would solve the problem:
public class People : DictionaryBase
{
public void Add(string key, Person newPerson)
{
Dictionary.Add(key , newPerson);
}
public void Remove(string name)
{
Dictionary.Remove(name);
}
public Person this[string name]
{
get
{
return (Person)Dictionary[name];
}
set
{
Dictionary[name] = value;
}
}
}
public class Person
{
private string name;
private int age;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
}
And in Main:
People peop = new People();
peop.Add("Josh", new Person() { Name = "Josh" });
I'm playing around with Dictionaries and the new fancy 4.0 dynamic types inside a dictionary.
I have a Dictionary:
Dictionary<dynamic, dynamic> dynamicDic
And I populate it like this:
dynamicDic.Add("First", new Class1());
dynamicDic.Add("Second", new Class2());
For the sake of testing/practising Class1 and Class2 are quite simple:
public class Class1
{
public string Element { get; set; }
public List<Class2> Class2 { get; set; }
}
public class Class2
{
public string Property { get; set; }
public string Field;
}
I create two other classes that map class1 and class2 and they are virtually the same so ClassMap1 and ClassMap2. I'll just include CalssMap1 though:
public class ClassMap1: BaseClassMap1
{
public ClassMap1()
{
var r = new Class1();
Children = new Dictionary<string, dynamic>
{
{"Element", r.GetType().GetProperty("Element")},
{"Class1", r.GetType().GetProperty("Class1")}
};
Name = "Root";
ObjectType = typeof (Class1);
Parent = "RootElement";
HasParent = false;
HasChildren = true;
IsClass = r.GetType().IsClass;
}
}
And I create a base class: BaseClass1()
public class BaseClass1
{
private String _Name;
public String Name
{
get { return _Name; }
set { _Name = value; }
}
private Type _ObjectType;
public Type ObjectType
{
get { return _ObjectType; }
set { _ObjectType = value; }
}
private String _Parent;
public String Parent
{
get { return _Parent; }
set { _Parent = value; }
}
private Dictionary<string, dynamic> _Children;
public Dictionary<string, dynamic> Children
{
get { return _Children; }
set { _Children = value; }
}
private bool _HasParent;
public bool HasParent
{
get { return _HasParent; }
set { _HasParent = value; }
}
private bool _HasChildren;
public bool HasChildren
{
get { return _HasChildren; }
set { _HasChildren = value; }
}
private bool _IsClass;
public bool IsClass
{
get { return _IsClass; }
set { _IsClass = value; }
}
}
I populate the classes with data, not really important what data :)
Yet when I try to access the values through a Linq statement:
var a = _classObjects.SingleOrDefault(x => x.Key == node.Name).Value;
a only gives me:-
a.Equals(), a.GetType(), a.GetEnumerator() or a.ToString()
I would like to be able to have it do this instead (with intellisense)...
a.Children
a.Name
a.HasParent
etc...
Anyone got any ideas where I'm going wrong?
Oops got that completely wrong... Sorry :|
Edited above...
dynamic classes are all about run-time (NOT compile-time) discovery. How do you expect Intellisense to know what to do?
Using dynamic classes incurs a high performance overhead. I really suggest that you make it: Dictionary<string, dynamic> dynamicDic.
Or define a MyBaseClass and make it: Dictionary<string, MyBaseClass> myDic.
MyClass.cs
public class MyClass
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
private string path;
public string Path
{
get { return path; }
set { path= value; }
}
}
When I return a List of Type MyClass, I would like to have, only the NAME Attribute.. Not the whole object.. How I can achieve this?
Something like:
List<MyClass> myClasses = new List<MyClass>();
return myClasses["Name"]; //<--- Only the Name
You could use Linq to only return the name but you will now have a List<string>:
return myClasses.Select(x => x.Name).ToList();
Alternatively you could create a new list of MyClass from your original and only populate the name attibute:
return myClasses.Select(x => new MyClass {Name = x.Name}).ToList();
If you just want a list of Names then the .Select(x => x.Name) mentioned by others is the best.
If however you want to return an object that only has the Name property, you could use an interface.
public interface IName
{
string Name { get; set; }
}
Then make MyClass implement the interface
public class MyClass: IName
{
//...snip
}
Then you can return a list of the interface
return myClasses.Cast<IName>();
public class myList : List<MyClass>
{
public MyClass this[string SearchedName]
{
get
{
return this.SingleOrDefault(mc => mc.Name == SearchedName);
}
}
}