from what i understand in other posts i know that my objects use same place in memory but how to separate these objects?
i tried to use new but it didn't work or i didn't used it correctly.
Note that i didnt paste setter and getter here.
class Supermarket
{
List<Product> _products = new List<Product>{ };
List<Customer> _customers = new List<Customer>{ };
}
class Customer
{
List<Product> _purchased= new List<Product>{ };
}
class Product
{
string _id;
string _name;
DateTime _expireDate;
int _cost;
int _count;
}
i add one Product in one Method.
Product product = new Product(...);
supermarket.Products.Add(product);
and in another method i want to copy the Product from Supermarket.Products
to Supermarket.Customers.Purchased. so i want a copy but i cant get it.
here i want to make Copy but it does not work.
Product product = supermarket.Products[productIndex];
supermarket.Customers[customerIndex].Purchased.Add(product);
now the problem is when i change Product properties in Customer class , Product properties inside Supermarket will change too.
for example
supermarket.Customers[customerIndex].Purchased.Last().Count = ...
//now the Product supermarket.Products[productIndex] will change too witch is unwanted
The reason why it is not working is because you are doing shallow copy by just adding the pointer of product object into the list, not all properties. So if you change one, another will be affected accordingly.
You can use deep copy following this answer, but this way you have to mark your class as [Serializable]. The simplest way which I think is to use Json serializer:
public static class CloneHelper
{
public static T Clone<T>(T source)
{
var serialized = JsonConvert.SerializeObject(source);
return JsonConvert.DeserializeObject<T>(serialized);
}
}
var copyProduct = CloneHelper.Clone<Product>(product);
Or simply, you can manage by yourself as the below code, then it works:
Product product = supermarket.Products[productIndex];
Product copyProduct = new Product() {
Id = product.Id,
Name = product.Name,
ExpireDate = product.ExpireDate,
Cost = product.Cost,
Count = product.Count
};
supermarket.Customers[customerIndex].Purchased.Add(copyProduct);
Related
I've searched a lot and I think this is possible, but I feel like I am just blocked from knowing how to properly format it.
I have a class representing a product that is a relation class from our CRM to Magento.
Inside the constructor, I have to do some stuff like this...
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
Product existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
this.id = existingMagentoProduct.id;
this.name = existingMagentoProduct.name;
... many of them ...
this.visibility = existingMagentoProduct.visibility;
this.extension_attributes.configurable_product_links = existingMagentoProduct.extension_attributes.configurable_product_links;
}
else
{
// its a new product, new up the objects
this.id = -1;
this.product_links = new List<ProductLink>();
this.options = new List<Option>();
this.custom_attributes = new List<CustomAttribute>();
this.media_gallery_entries = new List<MediaGalleryEntry>();
this.extension_attributes = new ExtensionAttributes();
this.status = 0; // Keep all new products disabled so they can be added to the site and released on a specific day (this is a feature, not an issue / problem).
this.attribute_set_id = netforumProduct.AttributeSetId;
this.visibility = 0;
}
}
It seems silly to have to initialize all of the properties like that. I could use a mapper but that seems like a bandaid. I have to see if the product exists in magento first, and populate its ID and values, otherwise whenever I save the product it creates an additional one.
I considered doing the class constructor calling a static method, but I couldn't get the syntax right.
It might just be too late and I need to think about something else for awhile.
If you must do it in the constructor, you can get rid of a lot of code by first setting 'default' values to the 'Product' properties. This will remove the need to do them in the constructor. Next, if you wanted to automatically set the class's properties, you can use reflection.
public class Product
{
public int Id { get; set; } = -1;
public List<ProductLink> Product_Links { get; set; } = new List<ProductLink>();
....
public int Visibility { get; set; } = 0;
public Product(IBaseProduct netforumProduct, MagentoClient client)
{
var existingMagentoProduct = client.GetProductBySku(netforumProduct.Code);
if (existingMagentoProduct != null)
{
foreach (PropertyInfo property in typeof(Product).GetProperties().Where(p => p.CanWrite))
{
property.SetValue(this, property.GetValue(existingMagentoProduct, null), null);
}
}
}
}
Though, I would like to point out that you probably shouldn't be using a REST client inside a class constructor, especially to just populate its data (also, you are performing a synchronous operation). It would be cleaner to have another layer that is responsible for populating this class using the client, and then use something like AutoMapper to map the data to it.
In this code, I am trying to check what rooms are available at the time that has been entered by the user. To test whether the room is free, I change the roomname to all the options and do a clash check. The problem is, is when I change the room name, it also updates it on my list of existingBookings. Is there a way to make sure that the existingBookings do not change?
var existingBookings = _context.Bookings.ToList();
var booking = await _context.Bookings.SingleOrDefaultAsync(m => m.BookingID == id);
List<Room> roomlist = new List<Room>();
roomlist = (from product in _context.Room
select product).ToList();
List<Room> availableRooms = new List<Room>();
foreach (var item in roomlist)
{
booking.RoomName = item.RoomName;
if (BusinessLogic.BookingChecker.DoesBookingClash(booking, existingBookings) == null)
{
availableRooms.Insert(0, new Room { RoomID = item.RoomID, RoomName = item.RoomName });
}
booking.RoomName = "UNDEF";
}
Thanks for your help!
In order to do so you have to create a new instance of the Booking. You can call the constructor and copy the necessary properties, or implement a ICloneable.Clone method.
public class Booking : ICloneable
{
public Booking Clone()
{
return new Booking() { RoomID = this.RoomID, etc. };
}
object ICloneable.Clone()
{
return this.Clone();
}
}
Then you call it:
booking = booking.Clone();
// use the new booking instance.
The way I fixed this, was to add a new bool field called proposed into the Booking.cs file. When creating the proposed booking, it will automatically set it to true. In my DoesRoomBookingClash I added an if statement to ignore a database entry if proposed was true. Once all the changes are made, proposed is set to false.
I'm brand new to MongoDB in C#.
I have created a very simple class which I would like to automatically insert into a collection.
How do I do that, if I don't want to map everything manually?
public class DummyClass
{
[BsonId]
public int Id { set; get; }
[BsonElement("first")]
public string First { set { _name = value; } }
[BsonConstructor]
public DummyClass()
{
Id = 2;
First = "1";
}
}
I had hoped I could do something like this:
_dbClient = new MongoClient();
_database = _dbClient.GetDatabase("testDB");
_collection = _database.GetCollection<BsonDocument>("Collection");
var doc = BsonDocument.Create(dummy);
_collection.InsertOneAsync(doc);
But it's no good. I get the exception:
System.ArgumentException : .NET type DummyClass cannot be mapped to BsonType.Document.
Parameter name: value
Any suggestions?
And I really don't want to do:
{
{"Id", "2"},
{"First", "1"},
}
EDIT:
I forgot this small line:
BsonClassMap.RegisterClassMap<DummyClass>();
It does wonders.
It makes sense to use BsonDocument when fields in collections don't match properties in your model class. Otherwise you should create collection mapped to your class.
_collection = _database.GetCollection<DummyClass>("Collection");
await _collection.InsertOneAsync(doc);
And don't forget about async/await methods in MongoDB.Driver.
You can use ToBsonDocument()
_collection.InsertOneAsync(doc.ToBsonDocument())
I am working on a C# application which consists of objects Department, Course, and Section. Each Department has many Courses, and each Course has many Sections. Currently I have three classes: Department, Course, and Section. Department contains some properties and then a List Courses, which contains the courses the department offers. Course contains some properties and then a List Sections, which contains the sections of the course. Is this a good way to have the code structured or should I be doing it a different way?
Secondly, when I instantiate a department in my application, I set some properties and then would like to begin adding courses to the List Courses defined in the Department class. However, I seem to be unable to simply do Department.Courses.Add(Course) from the application. What must I do within the Department class so that I may add objects to that list without breaking the principle of encapsulation?
An example of what I have with the list right now is:
class Department
{
// ......
List<Course> Courses = new List<Course>;
}
however Department.Courses is not available in the program code after the class has been instantiated (all other properties of the class are available).
Instantiate the internal Courses list inside the parameterless constructor of your class.
private List<Course> _coursesList;
public Department()
{
_coursesList = new List<Course>();
}
Also, another way to ensure the encapsulation is to provide a method on your Department class to add the courses to it instead of directly exposing the courses list. Something like
public void AddCourse(Course c) { ... }
// or (adding the feature of doing the method calls in a composable way)
public Course AddCourse(Course c) { ... }
// or
public void AddCource(String name, etc) { ... }
I think in your case it is not a good idea do directly exposes the List because the class List, may provide methods like, Add and Remove which could potentially creates an invalid state on your parent class. So if you choose to expose methods to manipulate the internal collections like I suggested, you could expose an array of Courses to your API clients (remember the arrays are read-only) so your API consumers won't be able to the create side effects on your department class.
public Course[] Courses {
get { return _coursesList.ToArray(); }
}
In addition, you could also implement the IEnumerable interface on your Department class. It would enable you to take advantage of the all LINQ extension methods available in C# 3.0.
I hope it helps,
Carlos.
Probably something Similar. There are several ways of soing this. depends upon what your requirements are.
public class Department
{
// Initialize the list inside Default Constructor
public Department()
{ courses = new List<Course>(); }
// Initialize List By Declaring outside and Passing with Dpartment Initilization
public Department(List<Course> _courses)
{ courses = _courses; }
List<Course> courses;
public List<Course> Courses
{
get
{
if (courses == null)
return new List<Course>();
else return courses;
}
set { courses = value; }
}
internal bool AddCourseToCourses(Course _course)
{
bool isAdded = false;
// DoSomeChecks here like
if (!courses.Contains(_course))
{
courses.Add(_course);
isAdded = true;
}
return isAdded;
}
}
public class Course
{
public Course(List<Subject> _subject)
{ subjects = _subject; }
List<Subject> subjects;
public List<Subject> Subjects
{
get { return subjects; }
set { subjects = value; }
}
}
// I do not get what do you mean by course "section", very general.
// used Subject instead, Change as you want just to give an idea
public class Subject
{
string name;
public string Name
{
get { return name; }
set { name = value; }
}
int creditHours;
public int CreditHours
{
get { return creditHours; }
set { creditHours = value; }
}
public Subject(string _name, int _creditHours)
{
name = _name;
creditHours = _creditHours;
}
}
public class TestClass
{
public void DoSomething()
{
// Subjects
Subject subj1 = new Subject("C#", 10);
Subject subj2 = new Subject(".Net", 10);
// List of Subjects
List<Subject> advancedPrSubjects = new List<Subject>();
advancedPrSubjects.Add(subj1);
advancedPrSubjects.Add(subj2);
// Course
Course advancedProgramming = new Course(advancedPrSubjects);
// Deliver authoroty to add Course to Department Class itself
Department dept = new Department();
dept.AddCourseToCourses(advancedProgramming);
}
}
There are better ways of doing this. have a look at these tutorials for better insight
http://www.csharp-station.com/Tutorials/Lesson07.aspx
http://www.functionx.com/csharp/index.htm
Hope it helps
As to your second question - without some code or more details its a bit hard - but i'll take a guess.
You're probably not actually creating the list, just declaring it
List<xxxx> _variable;
vs
List<xxxx> _variable = new List<xxxxx>();
You must create a list to be able to add to it (new List());
You sound as if you're on the right track.
Your second problem could be down to many things.
It could be as Ruddy says and that you're not creating the list.
It could also be that your Courses List is not public or that you haven't instanciated a new Course object to add.
I have a constructor something like the following:
using Microsoft.Data.Extensions;
public class Complaint
{
public int Id {get; set;}
public int Transcript {get; set;}
//... etc. ... Lots more properties
public Complaint(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
this.Id = complaint.Id;
this.Transcript = complaint.Transcript;
//... etc. ... Lots more properties to set
}
}
Is there a syntax in C# that would allow me to carry out the last part in one step instead of two? i.e. conceptually something like this:
this = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
}
Well, you could use a static method instead of a constructor:
public static Complaint FromId(int id)
{
var command = dataContext.CreateStoreCommand(
"dbo.stp_Complaint_Get",
CommandType.StoredProcedure,
new SqlParameter("Id", id));
return command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
});
}
Not inherently. You could store the complaint object inside the class, and have all the properties point off that rather than setting them all from the constructor.
eg
public class Complaint
{
private readonly {type of complaint} m_Complaint;
public int Id
{
get { return m_Complaint.Id; }
}
// ...etc
}
You could get more complicated if you don't have a setter on m_Complaint - keeping nullable backing fields, and check that before you access the m_Complaint properties
I believe you may try something like this:
var currentInstance = this;
var complaint = command.Materialize(x =>
new Complaint
{
Id = currentInstance.Id = x.Field("Id"),
Transcript = currentInstance.Transcript = x.Field("Transcript");
//... etc. ... Lots more fields from db
});
I don't think you can capture this in the closure, so using that currentInstance trick should help, however it may as well turn out to be redundant.
Besides, code such as that one is sort of obfuscated compared to your current solution. I believe that your code is pretty fine as it is.
I gather that you're trying to avoid setting all of those properties twice, because any change to the structure requires you to update the properties in two places, is that correct?. You could try to use some reflection to copy the properties from one instance to another.
var complaint = command.Materialize(x =>
new Complaint
{
Id = x.Field<int>("Id"),
Transcript = x.Field<string>("Transcript");
//... etc. ... Lots more fields from db
}
foreach (var prop in typeof(Complaint).GetProperties())
...
Have the complaint object as a member variable and the get/set properties accesses the underlying complaint's properties?