How to copy one element of a generic collection - c#

I need to copy one element of a generic collection and add it to the list. Something similar to this:
private List<CalculationResult> cantileverResults = new List<CalculationResult>();
cantileverResults.Add(cantileverResults[previousIndex]);
The problem with this solution is that when I modify the new element, the previousIndex element changes as well. I believe this is because they are reference-type, not value-type. How can I just copy (clone?) the information from one element to another without affecting each other any further?

You will need to create a new object when adding it.
This can be done in several ways - a helper method that takes an object of your type (CalculationResult) and returns a completely new one.
Perhaps have a constructor overload that does this.
There are many ways to achieve such a thing - implementing ICloneable and having the Clone method return a new object.
For example, if you were to create a constructor overload, this is how you could use it:
cantileverResults.Add(new CalculationResult(cantileverResults[previousIndex]));

Related

2 Generic list assignment

if class type list is there named
Collection<PurchaseOrderDetail> poDetails = new Collection<PurchaseOrderDetail>();
and another list with same type is there named _poH.PODetail
why _poH.PODetail = poDetails.ToList(); generates an error
Cannot implicitly convert type 'System.Collections.Generic.List'
to 'System.Collections.ObjectModel.Collection'
what is the solution for this, any explanation please.
All the reason behind the question is
_poH.PODetail = poDetails;
made poDetails.RemoveAt(Convert.ToInt32(e.RowIndex)); updates as well so I was searching for some thing like _poH.PODetail = poDetails.ToCollection();
According to the error message, _poH.PODetail is of type Collection, so assigning a list to it doesn’t work. But since poDetails is a collection itself, you can just assign it directly:
poH.PODetail = poDetails;
So you don’t actually need to call ToList() on it to convert it to a list.
There is no ToCollection method you could call on enumerables, but you could use the Collection constructor that takes a list to make it wrap that list and create a readonly collection:
new Collection(poDetails.ToList());
The short answer is simply that the ToList<T> extension returns an instance of List<T> class which, although similar, is not the same type as Collection<T>.
Basically this doesn't work for the same reasons you cannot set a string value to an integer variable.
One thing you can do though, is initializing the content of a new collection instance with an IList<T> instance. Therefore, the following should give you exactly what you want:
_poH.PODetail = new Collection(poDetails.ToList());
Also, as poke suggested, you might also want to assign the PODetail property with the poDetails variable itself.
_poH.PODetail = poDetails;
However, you must remember that Collection<T> is a reference type. This means that the objects in your collection won't be "copied" inside _poH.PODetail; instead, both poDetails and _poH.PODetail will be pointing to the exact same collection. Any changes done to one collection will automatically be reflected on the other.

How to use var to create an object using the GetType() method?

I'm fed up of writing the lines of code:
SomeUIElement ui = new SomeUIElement();
Grid.Children.Clear();
Grid.Children.Add(ui);
So I decided to write a method that would determine the type of the element then clear children and add it to the grid.
Something like this:
private void GridChildren(UIElement uc)
{
var element = uc.GetType();
Grid.Children.Clear();
Grid.Children.Add(element);
}
Which I could then call like this:
GridChilren(UserControl);
However I keep getting the error:
Argument 1: cannot convert from 'System.Type' to 'System.Windows.UIElement'
Any ideas on how I can determine the type of usercontrol being passed to my method?
EDIT:
I could call this by creating the instance first then clearing and adding to the grid. However that is not my question.
Yes, it would be more convenient, but for the purpose of this question assume that I ONLY want to understand how I can create an instance of a type without writing it out myself.
It seems as though you want to create an instance of a UIElement type and add it as the only child element of a grid.
The first line of your code (var element = uc.GetType()) returns an object of type Type, which results in the exception when you try to add it to the grid's Children collection (because that expects you to be adding a UIElement object, not a Type object).
You could have written your method like this:
private void GridChildren(UIElement uc)
{
Grid.Children.Clear();
Grid.Children.Add(uc);
}
And then you would call it like this:
SomeUIElement ui = new SomeUIElement();
GridChildren(ui);
but that's only saving you one line over the "longhand" version.
The following method will create and add a new UIElement to any kind of Panel control:
public void SetPanelChild<T>(Panel panel)
where T : UIElement, new()
{
T element = new T();
panel.Children.Clear();
panel.Children.Add(element);
}
The advantage of using generics here is that you don't need to bother with Activator.CreateInstance(). You would call the method like this:
SetPanelChild<TextBlock>(myPanel);
However when you find yourself creating controls programmatically like this there's probably a better way of doing it that leverages what WPF has to offer, such as the MVVM pattern and data binding.
You're looking for the Activator.CreateInstance() method, which will create an instance of a type using Reflection.
You will still need to cast it.
Alternatively (depending on how you're calling it), use a generic type parameter instead.

Calling a method with an index on ArrayList in c#

Ok here is my dilemma, I want to create an array of custom objects but then be able to do something like list[index].method call.
as an example:
program starts
program creates a master array which holds GenericClass< T >(param)
each generic class then creates an array of type T
I can get that part to work ok but then when I try to use my object methods such as
object[] MasterList = new object[MASTER_LIST_SIZE];
// add contents to MasterList
MasterList[index].setValueAt(MethodIndex, value);
I get a message that reads object has no method named setValueAt which requires one parameter(s)
I will admit that what I am trying to do is rather dumb and I could probably do it easier with reading a text file or something but if there is a way to do it like this I would like to know how or at least what I am missing.
There are a lot of unknowns about what you are doing but my best guess is that you need to cast the result to the type you need.
((GenericClass<T>)MasterList[index]).setValueAt(MethodIndex, value);

Duplicate an ObservableCollection Item

I want to duplicate a list item in an observablecollection. When I do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition];
It creates a copy of the specific list item but then they are linked in my UI. So if I change the new duplicated item's name, it changes the originals name. I know I could do each of the properties one by one (see below) but is there a way to just copy the entire item?
TreasureCards[TreasureCards.Count - 1].Name = TreasurecCards[CardPosition].Name;
TreasureCards[TreasureCards.Count - 1].Type= TreasurecCards[CardPosition].Type;
// etc
You aren't duplicating the object. You're creating a new reference to the object. There's still only one object; now there are two references to it in your collection, and any change to the object is reflected by both references.
To create a new object, you can call MemberwiseClone() on anything that derives from Object. This method returns a new instance, copying the values from all fields in the original object. So you'd do:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].MemberwiseClone();
There are two limitations with this method. First, it's a shallow copy, i.e. any reference fields in the original object have their values copied. So if a.Foo is a reference to a Bar object, a.MemberwiseClone().Foo will refer to the same Bar object. Second, the method just copies the fields; it doesn't call the new object's constructor. Depending on the design of the class, this is either unimportant or a Really Big Deal.
Usually, it's safer to make the class implement ICloneable and explicitly implement a Clone() method, e.g.:
public TreasureCard Clone()
{
return new TreasureCard
{
Name = this.Name,
Type = this.Type,
...
};
}
They aren't linked, they are the same instance. All you're doing is copying a reference to the same data to another position in the array.
What you need to do is implement some Clone method that makes a copy of the original instance but as another instance. This SO post might help.
Then you would do something like this:
TreasureCards[TreasureCards.Count - 1] = TreasureCards[CardPosition].Clone();

C# object initializers and collections

I'm trying to set up a class so that it's possible to initialize it using an object initializer, but it contains some collections. Ideally I'd like client code to be able to do:
MyClass myObj = new MyClass
{
Name = "Name",
Contents = new[]
{
"Item1",
"Item2"
}
}
However, where Contents needs to be a BindingList<string>. The underlying field stores a readonly reference to this list, and I'd like the setter to essentially do a Clear followed by AddRange to set the contents.
I can't make the Contents property an IEnumerable<string>, because client code wouldn't see the Add method, among many others, at least not without casting it first. I can't make it a BindingList<string> because if I set it, I need to construct a new binding list to pass to it.. this might be possible but I'd rather not introduce the inefficiency of construct a new BindingList<string> solely for the purpose of passing it to the property setter.
The ideal thing to be able to do would be to have the getter return a BindingList<string> and the setter accept IEnumerable<string>, but C# doesn't allow getters/setters on a property to have different types.
Oh, and implicitly casting between BindingList<string> and IEnumerable<string> is a no-no, so I can't do that either (http://blogs.msdn.com/b/peterhal/archive/2005/06/20/430929.aspx).
Is there any way around this?
C# initializer syntax will automatically call the Add method on your property's collection object. That won't call Reset() beforehand of course, but the object is still empty at that point, so it doesn't matter.
Does replacing the list have to use property set syntax? Having a setter replace the content of a collection without actually changing the collection object identity is very unexpected and will likely lead to bugs.
Create a custom collection class that derives from BindingList<string> and add an implicit cast from type string[]
I would recommed encapsulating the BindingList. In this situation go back to the old school way of creating objects so that you aren't creating unnecessary couplings. Favor good OO over language conventions.

Categories

Resources