Singleton class for multidimensional data - c#

I am using ASP.NET 3.5 with C#2008.
I have a table with data like below :
Id Code Message Details
-- ---- ------ ------------
1 111 xxxxx xxxxxxxxxxx
2 222 yyyyy yyyyyyyyyyy
3 333 zzzzz zzzzzzzz
and so on..
This is static data and I want to use it across application.
I have created a class with properties as below :
public class CodeDetails
{
public int Id { get; set; }
public int Code { get; set; }
public string message { get; set; }
public string details { get; set; }
}
And created another class codeDetailsList to whom I want to make as singletone as below :
public class codeDetailsList
{
private List<CodeDetailst> lstCodeDetailst;
private CodeDetailst()
{
lstCodeDetails = new List<CodeDetails>();
}
}
Now, what I want to do is, I want to add the items of above given tabular data into this singleton class's list and want to access it throughout application.
My question is how to add the items and access them?

Similar to Varun's answer, I just wanted to do a full implementation.
public class CodeDetailsList
{
private static readonly CodeDetailsList _instance = new CodeDetailsList();
public static CodeDetailsList Instance
{
get { return _instance; }
}
public ReadOnlyCollection<CodeDetails> lstCodeDetailst { get; private set; }
private codeDetailsList()
{
var masterList = new List<CodeDetails>();
masterList.Add(new CodeDetails(1, 111, "xxxxx", "xxxxxxxxxxx"));
masterList.Add(new CodeDetails(2, 222, "yyyyy", "yyyyyyyyyyy"));
//... And so on ...
//mark the list as read only so no one can add/remove/replace items in the list
lstCodeDetailst= masterList.AsReadOnly();
}
}
public class CodeDetails
{
public CodeDetails(id, code, message, details)
{
Id = id;
Code = code;
Message = message;
Details = details;
}
//Mark the setters private so no one can change the values once set.
public int Id { get; private set; }
public int Code { get; private set; }
public string Message { get; private set; }
public string Details { get; private set; }
}
The constructor for CodeDetailsList will be called once when you first try to access Instance (If you had other static members in the class the constructor would run on the first time any static member was called).
Because lstCodeDetaillst is a ReadOnlyCollection callers will not be able to add, remove, or replace objects in the list. Also because now CodeDetails has private setters all of the items in it are effectively "read only" too.

public class CodeDetailsList
{
public static readonly CodeDetailsList Instance = new CodeDetailsList();
public List<CodeDetails> ListCodeDetails { get; private set; }
private CodeDetailsList()
{
ListCodeDetails = new List<CodeDetails>
{
new CodeDetails { Id = 1, Code = 1, Details = "xxxxx", Message = "xxxxx"},
new CodeDetails { Id = 2, Code = 2, Details = "yyyyy", Message = "yyyy"} // ...
};
}
}
You should initialize the data in the constructor of codeDetailsList. The constructor should remain private to insure you do not create a new instance. Access the data using the Instance field on CodeDetailsList.

Did you intentionally omit the getInstance() method from your Singleton class? anyway...
The add might look something like:
CodeDetails codeDetails = new CodeDetails();
codeDetails.setId("id1");
codeDetails.setCode("code1");
codeDetails.setMessage("message1");
codeDetails.setDetails("details1");
(CodeDetailsList.getInstanceMethod()).add(codeDetails);
To access:
CodeDetails codeDetails = (CodeDetails)(CodeDetailsList.getInstaceMethod()).get(0);
You can put it in a loop if you have number of records
Hope this helps

Related

Add values to list in class c# [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 1 year ago.
I have a class with this:
public class myDataType
{
public class GetInvoice
{
public string InvoiceID { get; set; }
public string InvoiceNumber { get; set; }
public decimal InvoiceAmount { get; set; }
public List<InvoiceRow> Rows { get; set; }
}
public class InvoiceRow
{
public decimal RowQty { get; set; }
public string RowCode { get; set; }
public string RowDescription { get; set; }
}
}
And when I want to add data has th
using static test.myDataType;
...
private void LoadData()
{
GetInvoice Invoice = new GetInvoice();
Invoice.InvoiceID = "0a8625e5-62f6-4ad7-a8bf-ab04b1158392";
Invoice.InvoiceNumber = "Inv-001";
Invoice.InvoiceAmount = 100;
Invoice.Rows.Add(new InvoiceRow { RowQty= 1, RowCode = "C100", RowDescription = "Item C100"});
}
When try to add the row:
Invoice.Rows.Add(new InvoiceRow { RowQty= 1, RowCode = "C100",
RowDescription = "Item C100"});
Show me this error "System.NullReferenceException: 'Object reference not set to an instance of an object'"
I think i have a sintax o wrong way to do it
Can someone help?
Thanks in advance
It's not a syntax error, you just haven't initialised the list.
With
public List<InvoiceRow> Rows { get; private set; }
you've declared a place to hold the list, but haven't created the list itself.
(If an analogy helps, imagine you've drawn a line on the wall of your house where you're going to put up a bookshelf, but you haven't actually screwed the shelf to the wall yet - that's the situation your code is in).
If you want the list to always be available you can either initialise it automatically through the property declaration, or in the constructor of the class. Alternatively of course you could leave the calling code to initialise it.
This version just makes it part of the property declaration:
public List<InvoiceRow> Rows { get; private set; } = new List<InvoiceRow>();
You need first to initialize list Rows before you add element to it.
For example in GetInvoice class you can add:
public List<InvoiceRow> Rows { get; set; } = new List<InvoiceRow>();
List is reference type in C# so it needs to be initialized before being used.
If you want to do that in LoadData() method you can do in this way:
private void LoadData()
{
GetInvoice Invoice = new GetInvoice();
Invoice.InvoiceID = "0a8625e5-62f6-4ad7-a8bf-ab04b1158392";
Invoice.InvoiceNumber = "Inv-001";
Invoice.InvoiceAmount = 100;
Invoice.Rows = new List<InvoiceRow>();
Invoice.Rows.Add(new InvoiceRow { RowQty = 1, RowCode = "C100", RowDescription = "Item C100" });
}

How to access properties inside multiple model

When joining multiple models, I can't access its properties in controller.
public class BirdModel
{
public IEnumerable<BirdFile> BirdFils { get; set; }
public IEnumerable<BirdFileDetail> BirdFileDetails { get; set; }
}
public partial class BirdFile
{
public int ID{ get; set; }
public string Name{ get; set; }
}
Is it possible to access like this
BirdModel b = new BirdModel();
b.BirdFile.ID
You problem with b.BirdFile.ID is that you are trying to access the property or a collection of objects that you have not initialised.
You need to create an instance of the encapsulating class, BirdModel then create an instance of your BirdFile collection and add values to it. From there you can get the specific "BirdFile" within your collection via iteration and then access its properties.
A small example below:
class Program
{
static void Main(string[] args)
{
var bm = new BirdModel();
bm.BirdFils = new List<BirdFile>
{
new BirdFile {ID = 1, Name = "Bird A"},
new BirdFile {ID = 2, Name = "Bird B"}
};
bm.BirdFils.ToList().ForEach(x => Console.WriteLine($"Name: {x.Name}, ID: {x.ID}"));
Console.ReadKey();
}
}
public class BirdModel
{
public IEnumerable<BirdFile> BirdFils { get; set; }
}
public partial class BirdFile
{
public int ID { get; set; }
public string Name { get; set; }
}
BirdModel contains a collection of BirdFile, so to access them you should write something like:
// create a new model
BirdModel b = new BirtdModel()
// create the instance of BirdFile list
b.BirdFils = new List<BirdFile>()
// add an item (just an example)
b.BirdFils.Add(new BirdFile{ ID = 1, Name = "Bird1"}
// Access to the previously created BirdFile
BirdFile bf = b.BirdFils[0]

Are C# readonly field's allowed to be modify outside of the class?

I have a readonly object field that I set via a constructor parameter. If I modify the object, the field inside the class will also change, I guess it's a call by reference. Is there any way to do this better/prevent it?
private void Form1_Load(object sender, EventArgs e)
{
Product p = new Product() { Name="New" };
Store s = new Store(p);
p.Name = "MODIFY!";
MessageBox.Show(s.Show());//MODIFY!
}
public class Store
{
private readonly Product product;
public Store(Product product)
{
this.product = product;
}
public string Show()
{
return this.product.Name;
}
}
public class Product
{
public string Name { get; set; }
}
What you store in your readonly field is a reference. And that reference of course is readonly and never changed. But the content of the referenced object can still be changed.
Since Product seems to be a data-holding class, one approach might be to simply copy the content into a new instance:
public class Store
{
private readonly Product product;
public Store(Product product)
{
// Create a new Product instance that only this Store instance
// knows about
this.product = new Product { Name = product.Name };
}
}
Now the content of Store.product cannot be changed from outside as long as you don't export this instance.
But note that code inside the Store class may still be able to change the content.
If you don't want product inside of Store to change if you change the original instance, you have to make a copy before assigning it to the field:
public Store(Product product)
{
this.product = new Product() {Name = product.Name};
}
Alterantively, you could make Product a struct. Structs are always copied when passed to a method, and not passed by reference:
public struct Product
{
public string Name { get; set; }
}
Another option is creating an immutable version of Product:
public class Product
{
public string Name { get; set; }
public Immutable ToImmutable() => new Immutable(this);
public class Immutable
{
public Immutable(Product product) { Name = product.Name; }
public string Name { get; }
}
}
And now,
public class Store
{
private readonly Product.Immutable product;
public Store(Product product)
{
this.product = product.ToImmutable();
}
public string Show()
{
return this.product.Name;
}
}
Benefits? No one can mess around with product inside Store.

Adding to List replaces previous elements

I have a list that is used as a DataContext in a GridView.
This list is created with the following code:
private void initializeStarredHub()
{
List<StarredData> starredList = new List<StarredData>();
starredList.Add(new StarredData("ms-appx:///Images/Absence.png", "Sample Data 1"));
starredList.Add(new StarredData("ms-appx:///Images/Absence.png", "Sample Data 2"));
StarredHub.DataContext = starredList;
}
Where StarredData is
public class StarredData
{
public static string StarredImage { get; set; }
public static string StarredTitle { get; set; }
public StarredData() { }
public StarredData(string itemImageSet, string itemNameSet)
{
StarredImage = itemImageSet;
StarredTitle = itemNameSet;
}
}
The end result of the above is both starredList[0] and starredList[1] have "Sample Data 2" as the StarredTitle, meaning all previous values are overwritten by the latest set.
Why is this happening and how do I fix it?
That's because you declared static members in StarredData class, just remove the static keywords:
public class StarredData
{
public string StarredImage { get; set; }
public string StarredTitle { get; set; }
public StarredData() { }
public StarredData(string itemImageSet, string itemNameSet)
{
StarredImage = itemImageSet;
StarredTitle = itemNameSet;
}
}
You can fix it by removing the static keyword from your member definition.
Only one copy of a static member exists, regardless of how many instances of the class are created.
Check here: http://msdn.microsoft.com/en-us/library/79b3xss3.aspx

Theory on loosely coupled viewmodel

Can anyone please explain the theory on creating a loosely coupled viewmodel.
I have attached some example code below to try and explain what I mean.
I have 2 example classes just for this example
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Web.UI.Models
{
public class EmployerAddress
{
public string address { get; set; }
public string city { get; set; }
public string region { get; set; }
public string country { get; set; }
public string postZipCode { get; set; }
}
public class EmployerDetails
{
public string position { get; set; }
public string gender { get; set; }
public string dob { get; set; }
}
public class DisplayEmployerAddress : IDisplayEmployerAddress
{
public IEnumerable<EmployerAddress> employerAddr()
{
List<EmployerAddress> Data = new List<EmployerAddress>();
Data.Add(new EmployerAddress
{
address = "address1",
city = "city1",
region = "region1",
country = "country1",
postZipCode = "post zip1"
});
return Data;
}
}
public class DisplayEmployerDetails : IDisplayEmployerDetails
{
public IEnumerable<EmployerDetails> employerDetails()
{
List<EmployerDetails> Data = new List<EmployerDetails>();
Data.Add(new EmployerDetails
{
position = "trainee",
gender = "male",
dob = "22-08-1964"
});
Data.Add(new EmployerDetails
{
position = "trainee2",
gender = "male2",
dob = "22-08-1970"
});
return Data;
}
}
}
The code above has the interfaces:
IEnumerable<EmployerAddress> employerAddr();
IEnumerable<EmployerDetails> employerDetails();
I then use Ninject to bind the above.
kernel.Bind<IDisplayEmployerAddress>().To<DisplayEmployerAddress>().InSingletonScope();
kernel.Bind<IDisplayEmployerDetails>().To<DisplayEmployerDetails>().InSingletonScope();
At this point everything is OK, I could just change DisplayEmployerAddress etc and so long as all the methods etc match up the code will still work.
I then create a viewmodel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Web.UI.Models
{
public class EmployerDetailsViewModel
{
public string age { get; set; }
public IEnumerable<EmployerAddress> EmployerAddress { get; set; }
public IEnumerable<EmployerDetails> EmployerDetails { get; set; }
}
}
But now this would cause a problem as EmployerAddress is now tightly coupled, so if I change the code, it will now have to be updated in 2 places.
In my controller I have
public class HomeController : Controller
{
private readonly IDisplayEmployerAddress _address;
private readonly IDisplayEmployerDetails _details;
public HomeController(IDisplayEmployerAddress address,
IDisplayEmployerDetails details)
{
_address = address;
_details = details;
}
public ActionResult Index()
{
ViewBag.Title = "Title";
var Address = _address.employerAddr();
var Details = _details.employerDetails().AsEnumerable();
var Age = _details.employerDetails().FirstOrDefault().dob;
var employerModel = new EmployerDetailsViewModel
{
EmployerAddress = Address,
EmployerDetails = Details,
age = age.calAge(Age)
};
return View(employerModel);
}
I keep the controller lightweight as all the books I read say keep as little code as possible in the controller, so to calculate age I use a static class.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Web.UI.Models
{
public static class age
{
public static string calAge(string dob)
{
//Would cal age here
return "48";
}
}
}
So my question is 3 parts.
Is this example the correct way.
As my viewmodel is now tightly coupled, how do I make it loosley
coupled.
If I did not want to use a foreach loop how can I get each item out
of say EmployerDetails
This employer holds the position of #Model.EmployerDetails.position the gender is #Model.EmployerDetails.gender
<ul>
#foreach (var d in Model.EmployerAddress)
{
<li>#d.address</li>
<li>#d.city</li>
<li>#d.country</li>
<li>#d.region</li>
<li>#d.postZipCode</li>
}
</ul>
<ul>
#foreach (var dd in Model.EmployerDetails)
{
<li>#dd.position</li>
<li>#dd.gender</li>
<li>#dd.dob</li>
}
</ul>
So far This employer holds the position of #Model.EmployerDetails.position the gender is #Model.EmployerDetails.gender
Worked out question 3, changed code to #Model.EmployerDetails.FirstOrDefault().position
Hope the above example makes sense on what I'm trying to learn
Thanks
George
public class Employer
{
public int Id { get; set; }
}
public class EmployerAddress
{
public string Address { get; set; }
public string City { get; set; }
public string Region { get; set; }
public string Country { get; set; }
public string PostZipCode { get; set; }
public int EmployerId { get; set; }
}
public class EmployerDetails
{
public string Position { get; set; }
public string Gender { get; set; }
public string Dob { get; set; }
public int EmployerId { get; set; }
}
public class MyRepository : IMyRepository
{
public IEnumerable<Employer> GetEmployers()
{
return new List<Employer>
{
new Employer {Id = 1},
new Employer {Id = 2}
};
}
public IEnumerable<EmployerAddress> GetEmployeeAddresses()
{
return new List<EmployerAddress>
{
new EmployerAddress
{
EmployerId = 1,
Address = "address1",
City = "city1",
Region = "region1",
Country = "country1",
PostZipCode = "post zip1"
},
new EmployerAddress
{
EmployerId = 2,
Address = "address2",
City = "city2",
Region = "region2",
Country = "country2",
PostZipCode = "post zip2"
}
};
}
public IEnumerable<EmployerDetails> GetEmployeeDetails()
{
return new List<EmployerDetails>
{
new EmployerDetails
{
EmployerId = 1,
Position = "trainee",
Gender = "male",
Dob = "22-08-1964"
},
new EmployerDetails
{
EmployerId = 2,
Position = "trainee2",
Gender = "male2",
Dob = "22-08-1970"
}
};
}
}
public class EmployerChangedEvent
{
public EmployerChangedEvent(Employer selectedEmployer)
{
Employer = selectedEmployer;
}
public Employer Employer { get; set; }
}
public class EmployerViewModel
{
private readonly IEventAggregator _events;
private Employer _selectedEmployer;
// Configure Ninject properly to get those types
public EmployerViewModel(IEventAggregator events, IMyRepository myRepository)
{
_events = events;
Employers = myRepository.GetEmployers().ToList();
EmployerAddressViewModel = new EmployerAddressViewModel(_events, myRepository);
EmployerDetailsViewModel = new EmployerDetailsViewModel(_events, myRepository);
}
public List<Employer> Employers { get; set; }
public EmployerAddressViewModel EmployerAddressViewModel { get; set; }
public EmployerDetailsViewModel EmployerDetailsViewModel { get; set; }
public Employer SelectedEmployer
{
get { return _selectedEmployer; }
set
{
_selectedEmployer = value;
// this notifies the dependent view models in a loosley coupled way
_events.Publish(new EmployerChangedEvent(_selectedEmployer));
}
}
}
public class EmployerAddressViewModel :
IHandle<EmployerChangedEvent> // specifies which events shall be caught
{
private readonly IMyRepository _myRepository;
private Employer _selectedEmployer;
public EmployerAddressViewModel(IEventAggregator events, IMyRepository myRepository)
{
_myRepository = myRepository;
// this subscribes this view model to the passed event aggregator
// from your main view model (EmployerViewModel)
events.Subscribe(this);
}
public EmployerAddress EmployerAddress { get; set; }
public void Handle(EmployerChangedEvent message)
{
_selectedEmployer = message.Employer;
EmployerAddress = _myRepository.GetEmployeeAddresses()
.FirstOrDefault(e => e.EmployerId == _selectedEmployer.Id);
}
}
public class EmployerDetailsViewModel :
IHandle<EmployerChangedEvent> // specifies which events shall be caught
{
private readonly IMyRepository _myRepository;
private Employer _selectedEmployer;
public EmployerDetailsViewModel(IEventAggregator events, IMyRepository myRepository)
{
_myRepository = myRepository;
// this subscribes this view model to the passed event aggregator
// from your main view model (EmployerViewModel)
events.Subscribe(this);
}
public EmployerDetails EmployerDetails { get; set; }
public void Handle(EmployerChangedEvent message)
{
_selectedEmployer = message.Employer;
EmployerDetails = _myRepository.GetEmployeeDetails()
.FirstOrDefault(e => e.EmployerId == _selectedEmployer.Id);
}
}
internal class Program
{
private static void Main(string[] args)
{
// do this with Ninject
var employerViewModel = new EmployerViewModel(new EventAggregator(), new MyRepository());
// this selection should actually be user input
employerViewModel.SelectedEmployer = employerViewModel.Employers.First();
// select another one
employerViewModel.SelectedEmployer = employerViewModel.Employers.Last();
}
}
As I am not familiar with ASP.NET, my answer doesn't imply any of UI notifications.
I suggest Caliburn.Micro's event aggregator class here, because it solves your coupling problem nicely. This library is worth a look anyway for learning the MVVM pattern.
The IEventAggregator allows you to subscribe with instance of a class to an instance of the aggregator. If multiple view models share an instance of the event aggregator you can easily send events from one to another in a loosley coupled way.
I refactored your original code, to make it more fitting for the actual MVVM pattern (your first question, let's say this implementaion is more proper). I've added an Employer class, which is basically the main object. It only has an id. The EmployerDetails and EmployerAddress also have a new property EmployerId which is a reference to the Employer they belong to.
I have put all the stuff to query data in the MyRepository class!
For each of those three classes exist three seperate view models and they're only coupled through the event aggregator they share (answers your 2nd question). The EmployerViewModel manages the main data objects of type Employer and publishes an event as soon as the selected Employer changes. The new value is passed into the EmployerChangedEvent which then is caught by the view models which handle this certain kind of event (IHandle<EmployerChangedEvent). In their Handle() implementation the passed employer is put into a private field of the receiving view model.
This is just a console application which simulates user input, though try with putting break points on both of the handle methods, as the SelectedEmployer changes.
I think some kind of stuff I do in my Main() method should be done in your controllers. I have to mention that this code is just for showing the benefits of the MVVM pattern, it might be over abstracted in some cases. Also things like querying the repository efficiently are not covered at all!
I think my answer also solves your 3rd question, as I see no foreach is anymore needed.
Remember to reference Caliburn.Micro if you'd like to run this code. Just get it through NuGet or download it here.

Categories