Unwanted rewrite data in List - c#

I have problem with store data in list collection. If I add new data it rewrite old data, and in list is still only one item.
Here is main method, from this method I call method OpenChatScreen, It’s method of ChatScreenManager class where is root of problen.
private void OpenTabChatWindow(string nick)
{
try
{
new System.Threading.Tasks.Task(() =>
{
IDetailData oponent = new DetailData();
oponent = Service.DetailData(Account, nick);
Execute.OnUIThread((System.Action)(() =>
{
//here I call problem method OpenChatScreen method where is the problem,
//it use still the same reference on object opponent
if (ChatScreenManager.OpenChatScreen(true, Account, oponent, Account.DetailData.Info.Nick))
{
AddConversationHistory(nick);
}
}));
}
).Start();
}
catch (Exception exception)
{
MsgBox.ShowException(exception);
}
}
Code from ChatScreenManager class:
public IDictionary<string,object> ActiveChatScreens { get; set; }
or
public IList<string,> ActiveChatScreens { get; set; }
Problem is same if I use dictionary or list.
public bool OpenChatScreen(bool useTabChat, IAccount account, IDetailData oponent, string avatarNick)
{
if (!ActiveChatScreens.Contains(oponent.Info.Nick))
{
if(useTabChat)
{
//in this method - OpenTabChat is problem
OpenTabChat(account, oponent, avatarNick);
return true;
}
}
return false;
}
private void OpenTabChat(IAccount account, IDetailData oponent, string avatarNick)
{
if (!ChatShellViewModel.IsActive)
{
OpenChatShell();
}
ChatShellViewModel.OpenChatTab(account, oponent, avatarNick);
//here is the root of problem, it use same reference of object opponent
ActiveChatScreens.Add(oponent.Info.Nick);
}
So I pass from method OpenTabChatWindow object type of DetailData and store som string property in List in another class, but is use same reference on this object and rewrite data in list.
I try create new insatce of object:
IDetailData oponent = new DetailData();
oponent = Service.DetailData(Account, nick);
And pass this object to problem method, but it didn’t solve it.

Now if I understand your examples.
You add objects to ActiveChatScreens.
Could it be that you are reusing the same object in the call to OpenChatScreen in the first place.
Id so then opponent will change and any reference to it will also change before these methods is even called?
Remember objects are reference structures, even if you change the data in them, the reference is still the same.

Related

When I set an object using an Action<> the object assigned is always null

My goal is create an Action<> for set the configuration object in the constructor.
The Action<> that I have defined, set two configuration objects by reference, but the problem is that the assigned object is always null. I thought that internally, the objects, were assigned by reference but it seems that no.
In the example code, I have created a CarConfiguration in the main program and I try to set by reference this configuration to my new Car using an Action<> which defines the assignment between the main program CarConfiguration and the Car attribute configuration.
Why my car configuration attribute is always null even though is being assigned by reference in my Action<> method?
Main Class:
CarConfiguration carConfiguration = new CarConfiguration()
{
CarName = "Ferrari",
CarModel = "LaFerrari",
Spolier = true,
BuildDate = new DateTime(2018, 01, 01)
};
//Thats not work because the "conf" parameter is never assign in the Car constructor
Car myOwnCar = new Car(conf =>
{
conf = carConfiguration;
});
Console.WriteLine(myOwnCar.CarConfigurationText());
//That works, but is not my purpose do it like this!
Car myOtherCar = new Car(carConfiguration);
Console.WriteLine(myOtherCar.CarConfigurationText());
Configuration Class:
public class CarConfiguration
{
public bool Spolier { get; set; } = false;
public string CarName { get; set; } = String.Empty;
public string CarModel { get; set; } = String.Empty;
public DateTime BuildDate { get; set; } = default(DateTime);
}
Car Class:
public class Car
{
private CarConfiguration carConfiguration = null;
//That does not work because carConfiguration is not assigned in the Action as a reference
public Car(Action<CarConfiguration> configureCar)
{
configureCar(carConfiguration);
}
//That works!
public Car(CarConfiguration configureCar)
{
carConfiguration = configureCar;
}
public string CarConfigurationText()
{
StringBuilder strBuilder = new StringBuilder();
if (carConfiguration != null)
{
strBuilder.AppendLine(carConfiguration.CarModel);
strBuilder.AppendLine(carConfiguration.CarName);
strBuilder.AppendLine(carConfiguration.Spolier.ToString());
strBuilder.AppendLine(carConfiguration.BuildDate.ToString("mm-DD-yyyy"));
}
else
{
strBuilder.AppendLine("Car is not configure!");
}
return strBuilder.ToString();
}
}
Your action is assigning the configuration to the lambda parameter which has no effect as the parameter is an input value, it does not get returned out of the lambda. Objects are passed by reference, but references are copied to parameters in function calls, i.e. conf will receive a copy of the reference to carConfiguration when you call the action like so configureCar(carConfiguration);
Assigning and overwriting this local copy of the reference serves no purpose. You have to use the ref keyword to essentially pass a reference to the reference(variable) to the object. When assigning to a variable marked with ref it will overwrite the reference held in the original member variable and not the local variable inside the lambda. This is already demonstrated in the other answer.
The proper method to implement what you are trying to accomplish is not by passing references around but by configuring the object inside the action. If you want to use an existing configuration just pass the object as you've already done so. There is no need to write an action that accepts a reference to an object in an explicit manner.
public Car(Action<CarConfiguration> configureCar)
{
carConfiguration = new CarConfiguration();
configureCar(carConfiguration);
}
// This is the common configuration pattern seen in .NET
Car myOwnCar = new Car(conf =>
{
conf.CarName = "Ferrari";
conf.CarModel = "LaFerrari"
/** etc **/
});
If you want to copy values from an existing configuration, you can write a method to do so
public static class CarConfigurationExtensions
{
public static void CopyTo(CarConfiguration this source, CarConfiguration dest){
dest.CarName = source.CarName;
dest.CarModel = source.CarModel;
// etc
}
}
Car myOwnCar = new Car(conf => carConfiguration.CopyTo(conf));
But under no circumstance is writing an action that accepts a ref to a local variable a thing. Another alternative is to use a Func<CarConfiguration> like so, maybe if you want to do a lazy intialization.
public Car(Func<CarConfiguration> configurator)
{
_configurator = configurator;
}
private Func<CarConfiguration> _configurator;
private CarConfiguration _carConfiguration;
public CarConfiguration CarConfiguration =>
_carConfiguration ?? (_carConfiguration = _configurator());
Car myOwnCar = new Car(() => carConfiguration);
Note how the configuration is instantiated and stored- the first time it is accessed, perhaps the only time accepting a function in the constructor is useful.
Your code would work if instead of Action<CarConfiguration> you had used Action<ref CarConfiguration> (assuming this was legal), to allow passing the argument by reference. But there is no build-in Action<ref Τ>, so if you want one you should make it yourself:
public delegate void RefAction<T>(ref T arg1);
...and then use RefAction<CarConfiguration> instead of Action<CarConfiguration>.

Is there anyway to reconstruct an object inside itself?

I have a simple class that is intended for options of an winforms application. There should be a method that reset options to their default values. I know I can add a separate method to take care of this, but the code will be huge (If I add more options to the class) :
public SensorOptions()
{
ShowLabelMax = ShowLabelMin = ShowLabelAvr = ShowReceivedTextBox = true;
ChartMaxValue = 140;
ChartMinValue = -40;
ShowChartMinValue = ShowChartMaxValue = ShowChartAvrValue = ShowChartAvrLine = true;
LogFolder = Environment.SpecialFolder.MyDocuments.ToString();
LoggingEnabled = true;
}
public void ResetOptions()
{
this = new SensorOptions(); //can not do. 'this' is read-only
}
I mean I can copy/paste the code from constructor into ResetOptions() method. But is there any smarter ways to achieve this?
You cannot assign this because you may have references to this instance of your class in your program. If you could re-construct the object by re-assigning this, it would mean that all references to the old instance of the class become invalid.
No matter how many options you have in your class, you initialize each of them one or the other way (because you mention default value in your question - so you need to assign that default value somewhere at least once, probably in the constructor). Therefore, the solution to your problem is simple - move all initializers to the separate method and call it in the constructor, and then also call it every time you need to reset your options to their default values.
If any of your options are not assigned a default value explicitly, and use system default and you don't want to write option=default(optionType) for each option, you can use reflection to enumerate all fields/properties in that class and assign default values to them, like this:
public static object GetDefault(Type type)
{
if(type.IsValueType) return Activator.CreateInstance(type);
return null;
}
foreach(var field in this.GetType().GetFields())
field.SetValue(this, GetDefault(field.FieldType));
foreach(var prop in this.GetType().GetProperties())
prop.SetValue(this, GetDefault(prop.PropertyType));
Move all of the code from the constructor into the ResetOptions method, then in your constructor call the ResetOptions method. Your initialisiation code is only in one place then.
You have very simple architecture for your situation. In my opinion it would be better to apply a trick for this:
you have class for holding all your options (pseudo code):
class AllOptionsBackstage
{
public bool ShowLabelMax { get; set; }
public bool ShowLabelMin { get; set; }
public bool ShowLabelAvr { get; set; }
public AllOptionsBackstage()
{
// apply default values here
}
}
.....
class MyOptions
{
private AllOptionsBackstage _options;
public MyOptions()
{
Reset();
}
public bool ShowLabelMax
{
get{ return _options.ShowLabelMax; }
set{ _options.ShowLabelMax = value; }
}
public bool ShowLabelMin
{
get{return _options.ShowLabelMin;}
set{_options.ShowLabelMin=value; }
}
public bool ShowLabelAvr
{
get{ return _options.ShowLabelAvr;}
set{ _options.ShowLabelAvr = value; }
}
public void Reset()
{
_options = new AllOptionsBackstage(); // will reset all your options to default
}
}

method only adding to list if declared inside method

For some strange reason my code throws an object reference error when I attempt to add to the list declared in my class. My _machineName property is visible. The XML exists and has data. I am sure this has something to do with how I instantiated Machines inside the method. Any suggestions? I'm drawing a blank.
public class Machines
{
public List<string>_machineName { get; set; } //list I would like to add to
public Machines()
{}
public List<Machines> GetMachineList()
{
XmlDocument xml = new XmlDocument();
List<Machines> _machinesList = new List<Machines>();
List<string> str = new List<string>(); //List that works
string zdPath = GetZeroDeploymentPath();
zdPath = zdPath + #"\ZeroDeploymentService\XML\CatalogFile.xml";
using (XmlReader xmlReader = XmlReader.Create(zdPath))
{
xmlReader.MoveToContent();
while (xmlReader.Read())
{
if (xmlReader.IsStartElement())
{
switch (xmlReader.Name.ToLower())
{
case "machinename":
str.Add(xmlReader.ReadString().Trim()); //Works
_machineName.Add(xmlReader.ReadString().Trim()); //Fails
break;
}
}
}
}
return _machinesList;
}
It's because you never instantiate the list. In the constructor of your Machines class you need to add:
this._machineName = new List<string();
As an aside, a public property should not start with an underscore.
Your property
public List<string>_machineName { get; set; }
allows you to access _machineName, but you never actually create the List. If you add the following line to your constructor it will instantiate the List then you will be able to Add to it.
_machineName = new List<string>;
BTW, the name of a public property usually is a capital letter so I would change the name from _machineName to MachineName.
An ObjectReferenceException will be thrown when attempting to act on a reference of your _machineName list until it is instantiated, which happens inside of your GetMachineList() function.
You will have to move your instantiation of this object either outside of that method and into either a constructor or in the class body, or you will have to call that method before calling _machineName

method returning same object which was passed as parameter

Is it acceptable practice to pass an object into a method, then return the same object rather than creating a new object inside of the method itself?
As an example: if have an entity class as follows:
class UserDetails {
int UserID { get; set; }
string UserName { get; set; }
string UserAge { get; set; }
}
And then I pass an instance of this class to a method, as follows:
UserDetails UserInfo = new UserDetails();
UserInfo = Get_Details(UserInfo);
Is it reasonable for the method to do the following?
public UserDetails Get_Details(UserDetails user) {
// SQL Operations...
user.age = 32;
return user;
}
IMO, there is no need to return the object. Since it is passed to the method by reference, the caller already has a reference to the same object (with the updated values after the method completes).
On the other hand, what can be useful in some situations is a fluent-interface, where instance-methods of a class return the instance again, e.g:
class X
{
public X DoThis(int number)
{
// do something
return this;
}
public X DoThat(string name)
{
// do something else
return this;
}
}
This allows to write very readable code, such as:
var x = new X().DoThis(23).DoThat("asdf");
This can be useful with the builder pattern (when you want to build a complex object step by step).
As a very bad example:
class FooBuilder {
FooBuilder WithAge(int age);
FooBuilder WithUrl(Url url);
Foo ToFoo();
}
new FooBuilder().WithAge(12).WithUrl(new Url("http://www.happybirthday.com/").ToFoo();
In your particular case, I'd prefer to initialize everything in one go with the initializer syntax.
new User { Age = 45, UserName = "Bob", Id = 101 };
There is nothing horribly wrong with this but a couple of observations;
You are setting details inside of a method called get perhaps load is more appropriate.
If you are only passing in UserDetails because you want the id for your then the parameter should just be id instead. This keeps the interface cohesive.
It is generally considered bad form to modify a parameter object within a method, i.e., mutation principle.
Doing it like that is rather pointless, as the assignment that you do doesn't change anything.
Calling it like this:
UserInfo = Get_Details(UserInfo);
gives the same result as calling it and ignoring the return value:
Get_Details(UserInfo);
Returning the reference may only be confusing, leading someone to believe that the method returns a new instance, as that would be the only logical reason to return a reference.
It would make more sense to have that method in the class, so that you call it as:
UserInfo.Get_Details();
If your method is supposed to initialise the object, you would rather put the code it the constructor than calling it after creating the instance:
class UserDetails {
int UserID { get; set; }
string UserName { get; set; }
string UserAge { get; set; }
public UserDetails() {
Get_Details(this);
}
}
Then you just create the instance, and the constructor loads the data:
UserDetails UserInfo = new UserDetails();
This is a possible approach and when you have only ONE item to work one, the best, too. You might also consider to use ref, which creates a reference to the passed parameter
public void Get_Details(ref UserDetails user)
{
// SQL Operations. . .
user.age= 32;
}
this way, you don't pass a copy, but reference the object you passed in. But this can become quite obscure and is unnecessary in your case. See here for an insight.
You can fill your entity in its constructor method or another method inside entity class. It will be ready to use when created.
public class SomeClass
{
public string Field_1;
public int Field_2;
public SomeClass(int ID)
{
// Sql operations by ID or another value
// set fields
}
public AnotherMethod(int ID)
{
// Sql operations by ID or another value
// set fields
}
}
You might do well to look up the concepts of the Repository Pattern and OOD. In general, I prefer projections or fully loaded entities.
public UserDetailsProjection GetDetailsByUserId(Guid userID)
{
// Code goes here
return user;
}
Note: ref is not required, because all objects are passed by reference.

How can I create temporary objects to pass around without explicitly creating a class?

I frequently find myself having a need to create a class as a container for some data. It only gets used briefly yet I still have to create the class. Like this:
public class TempObject
{
public string LoggedInUsername { get; set; }
public CustomObject SomeCustomObject { get; set; }
public DateTime LastLoggedIn { get; set; }
}
public void DoSomething()
{
TempObject temp = new TempObject
{
LoggedInUsername = "test",
SomeCustomObject = //blah blah blah,
LastLoggedIn = DateTime.Now
};
DoSomethingElse(temp);
}
public void DoSomethingElse(TempObject temp)
{
// etc...
}
Usually my temporary objects have a lot more properties, which is the reason I want to group them in the first place. I wish there was an easier way, such as with an anonymous type. The problem is, I don't know what to accept when I pass it to another method. The type is anonymous, so how am I supposed to accept it on the other side?
public void DoSomething()
{
var temp = new
{
LoggedInUsername = "test",
SomeCustomObject = //blah blah,
LastLoggedIn = DateTime.Now
};
// I have intellisense on the temp object as long as I'm in the scope of this method.
DoSomethingElse(temp);
}
public void DoSomethingElse(????)
{
// Can't get my anonymous type here. And even if I could I doubt I would have intellisense.
}
Is there a better way to create a temporary container for a bunch of different types, or do I need to define classes every time I need a temporary object to group things together?
Thanks in advance.
Tuple may be the solution you're looking for.
public void DoSomething()
{
var temp = Tuple.Create("test", "blah blah blah", DateTime.Now);
DoSomethingElse(temp);
}
public void DoSomethingElse(Tuple<string, string, DateTime> data)
{
// ...
}
The rules state that
You cannot declare a field, a property, an event, or the return type
of a method as having an anonymous type. Similarly, you cannot declare
a formal parameter of a method, property, constructor, or indexer as
having an anonymous type.
Personally, I would just bite the bullet on this one to preserve compile time integrity.
The Tuple is the clean way to go, but just to let you know that C# doesn't let you down even otherwise and to answer the question, this is how DoSomethingElse could look like:
private static void DoSomething(object temp)
{
var typedTemp = CastToType(temp, new
{
LoggedInUsername = "dummy",
SomeCustomObject = "dummy",
LastLoggedIn = DateTime.Now
});
Console.WriteLine(typedTemp.LastLoggedIn);
}
private static T CastToType<T>(object obj, T type)
{
return (T) obj;
}
PS: Don't -1, I won't use this, I don't ask you to use this :)
You can pass around anonymous types by declaring the parameter dynamic under C# 4. That said, I would not recommend this except in private methods. You lose type-safety, IntelliSense, and readability.
You could also use non-generic container classes such as ArrayList. But then you're back to casting, which is why we got generics in the first place.
Personally I'd create the class. Look to see if there's an abstraction that covers all your types and declare that as an interface, then use a generic container of that type.
public class GenericObjs
{
private List<object> objs = new List<object>();
public List<object> Objs { get { return objs; } set { objs = value; } }
public GenericObjs(List<object> Objs) { objs = Objs; }
}
You could include List String and a constructor for List String ...
I just don't come across the need for throw away classes. If the business object has structure then a class is the way to define and enforce that structure and it is not much code.

Categories