I have a class which have a list
public static List<bar> tempList = new List<bar>();
public static Foo foo = new Foo();
public class bar(){
public string name;
public int age;
}
public class Foo(){
public List<bar> lBar = new List<bar>();
}
I have several textbox controls: age1, age2
on textChange on each control a create a new object
/*------------------------------------------------------------------
Following code: I want runtime calculation for a logic i did with age.
also need to create a new object using the inputs
------------------------------------------------------------------*/
age1_textChaned(...){
createObj( );
}
age2_textChaned(...){
createObj( );
}
private void createObj(){
if(tempList.Count != 0)
tempList.Clear();
if(age1.Text != "")
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
if (age2.Text != "")
tempList.Add(new bar("name2", Convert.ToInt32(age2.text));
}
Then i have a button btn1 which will create the object then clear the content of textbox.
btn1_Click(...){
foo.lBar = tempList;
clearFields(); //here lies the question, once i clear the fields,
//somehow it is still affecting the values in foo.lBar;
}
private void clearFields(){
age1.Text = "";
age2.Text = "";
}
so when i do this
btn2_Click(...){
foreach(bar b in foo.lBar){ //foo.lBar is empty i dont know why
...
}
}
my current solution on btn1_click i have this
foreach(bar b in tempList)
foo.lBar.Add(b); // instead of foo.lBar = tempList
is the foo.lBar = templist causing these changes?
snippet is only a simpler version of an entirely different project.
Objects in C# are passed around by reference unless specified otherwise.
For example, here is the code you are running and how it works behind the scenes :
// create a new location in memory and refer to it using the variable tempList
public static List<bar> tempList = new List<bar>();
// add a new item to the list
tempList.Add(new bar("name1", Convert.ToInt32(age1.text));
// make the variable foo.lBar to also refer to the same spot in memory as tempList
foo.lBar = tempList;
// clear the spot in memory containing the list
tempList.Clear();
That last line affects both the tempList variable and the foo.lBar variable because they both refer to the same location in memory.
The solution to avoid this is to create a new copy of an object in memory so the two variables are pointing to two separate instances in memory, and clearing one does not clear the other.
That is why your current solution works
// add the memory location of each item in tempList to foo.lBar's list
foreach(bar b in tempList)
foo.lBar.Add(b);
Note that if you call tempList.Clear() it will only clear the memory references being stored in tempList, however the actual objects will still exist in memory elsewhere.
Also with this solution if you did something like this :
tempList[0].name = "A changed name";
it would change the name property of the item in the foo.lBar list as well, since they both share the same reference in memory.
Related
I have a two class properdata and pprosecnddata both classes having property
I want to access product property from properdata class list object. How is it possible,below is my sample code
pupilc class ProperData
{
public string code{get;set;}
public List<ProSecndData>Secnd{get;set;}
}
public class ProSecndData
{
public string product{get;set;}
}
I am trying to call property like that
class Program
{
static void Main(string[] args)
{
ProperData.Secnd.Product = "Hello";
}
}
you cannot directly access property of Secnd as it is a list
you need to iterate or select the index of the List<Secnd>
you must initialize Secnd first and Secnd should have items in the list
properData.Secnd = new List<ProSecndData>();
so it can be access via
foreach(var second in properData.Secnd)
{
second.product = "hello";
}
//or
for(var i = 0; i < proderData.Secnd.Count(); i++)
{
properData.Secnd[i].product = "hello";
}
//or
var index = //0-length of list;
properData.Secnd[index].product = "hello";
if you want to have items first then add first on your Secnd List
properData.Secnd = new List<ProSecndData>();
properData.Secnd.Add(new ProSecndData{ product = "hello"});
then you now can iterate the list by using methods above
You are trying to access list as a single object, which is not possible.
you need to create single instance of your list class and then you can add string in that single instance.
properData.Secnd = new List<ProSecndData>();
ProSecndData proSecndData = new ProSecndData();
proSecndData.product = "Hello";
properData.Secnd.Add(proSecndData);
Actually I know the answer already, you have not created a constructor to initialise your List.
I'm guessing you get a object null ref error?
Create the constructor to initialise your list and it should be fine.
But in future, please post the error message (not the whole stack, just the actual error) as well as all the code required to repeat the issue. Otherwise you run the risk of getting your question deleted
(It should be deleted anyway because it could be considered a "what is a null ref err?" question).
Also you are accessing an item in a list like the list is that item (should be more like: ProperData.Secnd.elementAt(0).product, please also note the capitalisation of 'product' in the model vs your code.
I have an issue with trying to modify a list of Transactions within a foreach. I have created copies of the list passed into my method, made it read only, and yet when I try to change a value within any of the lists it changes that value within them all. Some type of memory link? I am unsure how to resolve this issue.
My program starts by declaring a class called Transaction (which is a generic class having Name, Value, Formatting), then I have subClasses :Transaction. I create a TransList (from public class TransList : IEnumerable) which has an object instance of each subClass. So a TransList would include a class named TranID, Amount, OrderID, Time, CardType, Comment1, Comment2. Each value of these subclasses could be string, decimal, DateTime. After that a list of TransParts is created it is then put into a larger list called processTrans.
So Comment2 is the element with a payment citation number and if there is more than one number in there I want to separate that into more than one TransList add those new TransLists to processTrans and remove the non-separated one. From my code below, having tried every strategy, run-time modification occurs to not only the intended processTrans but also to tempProcessTrans, addOn, tran, tranPart.
If processTrans that is passed into method looks like this in the debugger locals
processTrans [0] _Items TranID.Value = SD234DF and Comment2 = adf;wer;
Then the output should be
processTrans [0] _Items TranID.Value = SD234DF-1 and Comment2.Value=adf
processTrans [1] _Items TranID.Value = SD234DF-2 and Comment2.Value=wer
I currently get
processTrans [0] _Items TranID.Value = SD234DF-1-2 and Comment2.Value=wer
processTrans [1] _Items TranID.Value = SD234DF-1-2 and Comment2.Value=wer
public static List<TransList> SeperateMultiCitations(List<TransList> processTrans) //change TransList seperating Multiple Citations
{
List<int> indexes=new List<int>();
IList<TransList> tempProcessTrans = processTrans.AsReadOnly(); //this didn't help
List<TransList> addOn= new List<TransList>(); //copy list didn't stop from changes to occur in processTrans at same time
foreach (TransList tran in tempProcessTrans.ToList())
{
TransList copyTransList = tran;
foreach (Transaction tranPart in tran.OfType<Comment2>())
{
if (new Regex(";.+;").IsMatch((string)tranPart.Value, 0))
{
string[] citations = Regex.Split((string)tranPart.Value, ";").Where(s => s != String.Empty).ToArray();
int citNumb = 1;
indexes.Add(tempProcessTrans.IndexOf(tran));
foreach (string singleCitation in citations)
{
addOn.Add(ChangeTrans(tran, singleCitation, citNumb++)); when this line runs changes occur to all lists as well as trans, tranPart
}
break;
}
}
}
foreach (int index in indexes.OrderByDescending(x => x))
{
processTrans.RemoveAt(index);
}
processTrans.AddRange(addOn);
return processTrans;
}
public static TransList ChangeTrans(TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
temp.Value += "-" + citNumb;
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
temp.Value = singleCitation;
}
foreach (Transaction temp in copyTransList.OfType<Amount>())
{
//temp.Value = DboGrab(temp);
//temp.Value = amount;
}
return copyTransList;
}
public class Transaction : TranInterface
{
public string Name;
public object Value;
public string Formating;
public Transaction(string name, object value, string formating)
{
Name = name;
Value = value;
Formating = formating;
}
}
class TranID : Transaction
{
public TranID(string Name, string Value, string Formating) : base("Transaction ID", Value, "#") { }
}
public class TransList : IEnumerable<Transaction> //not to add all the lengthy parts here but this just allows for adding the parts and iterating through them in the foreach statements
{}
The behavior you're seeing is an inherent feature of reference types. When you call the ChangeTrans() method, the reference returned by that method is exactly the same as the one you passed in, which is that original value tran. Within the inner loop, the value of tran never changes, so on each iteration of the loop, you are modifying the same object over and over, adding it to your addOn list with each iteration.
This has two undesirable effects:
There is no difference between each element in the addOn list. They are all identical, referencing the same single object.
Any modification of any single element in the addOn list, or via the original reference to that single object, is visible via every other reference to that same single object. I.e. via all of the other elements in the list, and even that original reference in the tran variable (and of course, the copyTranList variable, which was assigned to the value of tran).
Without a more complete code example, it's not possible to know for sure what the best solution would be. However, one naïve solution would be to simply change your ChangeTrans() method so that it is responsible for making the new copy:
public static TransList ChangeTrans(
TransList copyTransList, string singleCitation, int citNumb) //add ConFee
{
TransList newTransList = new TransList();
foreach (Transaction temp in copyTransList.OfType<TranID>())
{
Transaction newTransaction = new TranID();
newTransaction.Value = temp.Value + "-" + citNumb;
newTransList.Add(newTransaction);
}
foreach(Transaction temp in copyTransList.OfType<Comment2>())
{
Transaction newTransaction = new Comment2();
newTransaction.Value = singleCitation;
newTransList.Add(newTransaction);
}
return newTransList;
}
Note: I have no idea if the above actually would compile, or if it actually copies all of the values needed. I reiterate: since you have not shown the TransList or Transaction data structures, it's not possible to know what all in them needs to be copied, nor what the best way to copy those values would be.
That said, note in the above example that this version of the method:
Creates an entirely new instance of the TransList object, storing the reference in newTransList.
For each Transaction value to be modified, it creates an entirely new instance of Transaction (using the appropriate type), assigning to that instance's Value property the modified value.
For each of those new Transaction objects, it adds the object to the newly-created TransList object referenced by the newTransList variable.
Finally, it returns that newly-created TransList object, rather than the one that was passed to the method.
Presumably you know what the correct way to add Transaction elements to TransList object, as well as whether there are other members in a Transaction object that would need to be copied. The above is simply a basic illustration of where and how you can modify your code so that you do the "deep copy" needed to avoid the problem you're describing.
can some one explain to me how to break the chain with a NEW statement?
Let me clarify the chain I’m talking about. When I call to a class I use the NEW statement like so
Myclass x =new Myclass();
My understanding is this creates a new empty instance of Myclass. Now correct me if I’m wrong but having a new empty instance one should be able to add what ever data the class supports?
I use this lot and would think the above to be true until adding data in such a manner
Myclass x =new Myclass();
//oldMyclass being old data that needs to be changed then
//added back to the class as a new or duplicate entry
x = oldMyclass[1];
//we change the data
x.red= 0x54;
//we add it back
oldMyclass.add(x);
All is good until we edit the data after adding it say we need to change another value.
We access the oldMyclass and select the proper item say its index is 2 but we only want to change the values of index 2
Myclass x =new Myclass();
x = oldMyclass[2];
x.red=soemvalue;
oldMyclass[2] = x;
This will change the red value of both index 1 and index 2. How can I break the chain between index 1 and index 2?
I think I might have over simplified this question let me know.
Thanks for any information.
Edit: Here is the copy method that I tried
public static Items.SavedItem Copy(Items.SavedItem old)
{
Items.SavedItem x = new Items.SavedItem();
x.generator = old.generator;
x.hireling_class = old.hireling_class;
x.id = old.id;
x.item_slot = old.item_slot;
x.owner_entity_id = old.owner_entity_id;
x.socket_id = old.socket_id;
x.square_index = old.square_index;
x.used_socket_count = old.used_socket_count;
return x;
}
So let's say, for arguments sake, you have a class like this:
public MyClass
{
public string Foo { get; set; }
}
And you have a collection
List<MyClass> myList = new List<MyClass>();
Now you create an instance of MyClass
MyClass obj1 = new MyClass() { Foo = "bar" };
Now if you do this:
myList.Add(obj1);
myList.Add(obj1);
You now have a list with TWO members, but they happen to be the same object. Whats stored in the list is a reference to the object you added, not the object itself. So myList[0] == myList[1]
Now if you did this:
MyClass item = myList[1];
And then:
item.Foo = "something else";
Both the item at index 1 and the item at index 0 will have 'Foo == "something else"' because they are the same item.
Another point that seems to be confusing you is this: myList has two items. If I do this:
MyClass item = myList[0];
myList still has two items. Indexing a collection doesn't remove it and because of that, there is no need to add the item back to the list. It's already there. All I've done is copy the reference from myList to a variable named item.
There are collections (Stack and Queue for example) that do work on the principle that you will remove items and (potentially) add them back, but List doesn't work that way.
So if you wanted to add multiple objects to myList you need to create multiple objects with the new keyword. For example:
List<MyClass> myList = new List<MyClass>();
MyClass obj1 = new MyClass() { Foo = "bar" };
myList.Add(obj1);
obj1 = new MyClass() { Foo = "something else" }; // Note: I've reused the variable, but this is a *new* object
myList.Add(obj1);
Or, if you don't need the new object assigned to a variable, you can simply if to:
List<MyClass> myList = new List<MyClass>();
myList.Add(new MyClass() { Foo = "a" });
myList.Add(new MyClass() { Foo = "b" });
Or even more compactly, you can exploit the collection initialization syntax and simply:
List<MyClass> myList = new List<MyClass>()
{
new MyClass() { Foo = "a" },
new MyClass() { Foo = "b" }
}
If you want to copy an object from your list, then you need to copy each property (and if it contains other objects, you may need to copy them too). There are various ways to do this, IClonable or a copy constructor are examples, but it basically comes down to, at some point, doing something like this:
myCopy.Foo = myOriginal.Foo;
myCopy.Bar = myOriginal.Bar;
// repeat for all properties that you want to copy.
Now assuming that Foo and Bar aren't also reference types, you have a copy. If they are reference types, you have a copy, but myCopy.Foo and myOriginal.Foo are still pointing at the same object.
I'm trying to add a new OldFlatFile to OldFlatFileList which works but not on adding new one. I can not see error and I don't know if there's something wrong with the code below?
OldFlatFileList count is same as before and after adding:
var selectedPackage = FlatFileHelper.GetSelectedPackage(OldFlatFileList);
var primaryFeature = new PrimaryFeatures(){ DataTypeCode = "abc" };
OldFlatFileList.ToList().Add(
new OldFlatFile
{
new OldFlatFileEntry
{
InformationFields = selectedPackage.InformationFields,
PrimaryFeatures = primaryFeature,
SecondaryFeatures = null
}
});
private IEnumerable<OldFlatFile> OldFlatFileList
{
get { return Session[SystemConstant.OldFlatFileListKey] as List<OldFlatFile>; }
set { Session[SystemConstant.OldFlatFileListKey] = value; }
}
public class OldFlatFile : List<OldFlatFileEntry>
{}
OldFlatFileList.ToList() creates new instance of list (which will have copies of items from original list). Then you are adding new object to that new list, but you don't save reference to new list in any variable. So your new list with added item simply will be collected by garbage collector. Original list will stay unchanged (because you didn't add item to it).
Thus you can't add items to variable of IEnumerable<T> type (it supports only enumeration), I suggest you to change OldFlatFileList property type to List<OldFlatFile>, or IList<OldFlatFile> or ICollection<OldFlatFile>. Then simply call:
OldFlatFileList.Add(new OldFlatFile { ... });
That will modify your original list.
I am new to C#, so bear with me. I have a problem in c# where I can't decide on whether I need a class or a struct. I'm creating a List of either the class or struct and adding elements to it. If I use a struct, then I can add an item, alter it, and add it again and the changes will be seen because it is passed by value. The problem is, structs are not mutable so I can't edit any of the elements later. If I use a class, then if I add an item and alter it, all the items in the list get changed. I have to create a new instance of the object each time if I want it to be different. But I have an object that I only want to change one item in, so I have to copy all the other items to the new object?! WHY? Is there a better solution?
This code illustrates my problem:
namespace TestError
{
public partial class Form1 : Form
{
private List<Thing> lst;
private Thing obj;
public Form1()
{
InitializeComponent();
lst = new List<Thing>();
obj = new Thing();
obj.a = "bla";
lst.Add(obj);
//obj = new Thing();
obj.a = "thing";
lst.Add(obj);
foreach (Thing t in lst)
listBox1.Items.Add(t.a);
}
}
class Thing
{
public string a;
//problem is there are many more items here that don't change!
}
}
Why the struct doesn't work:
namespace TestError
{
public partial class Form1 : Form
{
private List<Thing> lst;
private Thing obj;
public Form1()
{
InitializeComponent();
lst = new List<Thing>();
obj = new Thing();
obj.a = "bla";
lst.Add(obj);
lst[0].a = "new"; //error. if i change it to class, it works.
obj.a = "thing";
lst.Add(obj);
foreach (Thing t in lst)
listBox1.Items.Add(t.a);
}
}
struct Thing
{
public string a;
}
}
Class is the way to go. I've never touch the struct type since I left college.
For the Thing class, you stated" there are many more items here that don't change!". Is that mean the values are fixed or the values are based on the initial object. If the values are fixed, you can assigned some default values in the class.
If the values are based on the initial object, I don't see the hassle of passing the variable while adding the object to the list.
The problem is, structs are not mutable so I can't edit any of the elements later.
This is simply not true; don't get me wrong, I think it is a really bad idea to do what you are trying to here, and I think a class with a Clone() method would be the best solution, but the reason you are thinking this is precisely due to value-type semantics. You need to keep in mind that list indexers (the [0]) are methods - and not direct access; consider:
lst[0].a = "new";
what this line would do, if it compiled, is:
fetch a copy of the object out of the list (this is now a completely isolated and separate copy)
change a field on the copy
discard the copy
The compiler knows that this pretty certainly is not what you intended, so it prevents you making a mistake; the usage there would be:
var tmp = lst[0];
tmp.a = "new";
lst[0].a = tmp;
Oddly enough, though - if lst were an array, then that would work - arrays allow for direct in-situ editing:
lst[0].a = "new";
would compile. HOWEVER, PLEASE DON'T DO THIS:
mutable structs are a bad idea and will cause lots of confusion in your code
public fields are also a bad idea
large structs are also a bad idea
Like I say, my advice here would be a class; if you want convenient copy semantics, then add a Clone() method