Can't add Lazy initialized object to Generic List - c#

I have generic list:
class BooksRegister <T>
{
private T[] Register;
public int Count { get; set; }
public BooksRegister()
{
Register = new T[100];
Count = 0;
}
public void Add(T value)
{
if (Count >= 100)
{
return;
}
Register[Count] = value;
Count ++;
}
}
then object class:
class Book
{
public String Author { get; set; }
public String Title { get; set; }
public int Quantity { get; set; }
public Book(String aut, String pav, int kiek)
{
this.Author = aut;
this.Title = pav;
this.Quantity = kiek;
}
public override string ToString()
{
return Author + " \"" + Title + "\" " + Quantity;
}
}
Then goes my Data class where I am reading information from file. I need to implement lazy initialization of object but when I do so I can't store my object in List.
public static void ReadBooks(BooksRegister<Book> allBooks)
{
StreamReader sr = new StreamReader("ListOfBooks.txt");
string line = "";
while ((line = sr.ReadLine()) != null)
{
string[] words = line.Split('|');
String tempAuthor = words[0];
String tempTitle = words[1];
int quant = Convert.ToInt32(words[2]);
Lazy<Book> tempas = new Lazy<Book>();
tempas.Value.Author = tempAuthor;
tempas.Value.Title = tempTitle;
tempas.Value.Quantity = quant;
allBooks.Add(tempas); // error here
}
How can I solve this problem? I have to use lazy initialization necessarily

If you must use lazy there are 2 ways:
You change you lazy initialization code with:
Lazy<Book> tempas = new Lazy<Book>(() => new Book(tempAuthor, tempTitle, quant));
allBooks.Add(tempas.Value);
What it does is defines an expression on how to initialize the book. This is a bad approach because you initialize lazy object on line one, and you initialize it on the second line, which basically makes using Lazy<Book> useless.
Another approach would be to change the method signature to
public static void ReadBooks(BooksRegister<Lazy<Book>> allBooks)
In this case your lazy initializing code would look like this:
Lazy<Book> tempas = new Lazy<Book>(() => new Book(tempAuthor, tempTitle, quant));
allBooks.Add(tempas);
One thing that is missing in this case is how to access Book in BooksRegister, as now it is write only object - you can add value, but there is no way to read it from outside the class.

Related

Null reference c#

Im writing a code where you can search a name and the subjects teaches will pop-up etc..
however I'm not really sure why but i'm getting Object reference not set to an instance of an object error im missing something i know, can someone help me? i tried different methods didn't really work... heres my code :
public partial class MainWindow : Window
{
Course my = new Course();
public class Course
{
public string[] Name { get; set; }
public string[] Subject { get; set; }
public string[] Hour { get; set; }
public Course(string[] name, string[] subject, string[] hour)
{
this.Name = name;
this.Subject = subject;
this.Hour = hour;
}
}
public MainWindow()
{
InitializeComponent();
my.Name[0] = "Ali";
my.Name[1] = "Sefer";
my.Subject[0] = "INFORMATIKA";
my.Subject[1] = "ENGLISH";
my.Hour[0] = "12";
my.Hour[1] = "22";
}
private void searchButton_Click(object sender, RoutedEventArgs e)
{
Find();
}
private void Find()
{
int index = 0;
string wanted = wantedName.Text;
while (my.Name[index] != wanted && (my.Name[index] != "END"))
{
index++;
}
if (my.Name[index] == wanted)
{
outputLabel.Content = " " + my.Name[index] + " " + my.Subject[index];
}
else
{
outputLabel.Content = "Name not found";
}
}
}
}
You are using arrays without initializing them. While you have defined a constructor for your Course class that takes values for the arrays, you are using the default constructor. Try calling your own constructor with arguments like
Course my = new Course(new string[2], new string[2], new string[2]);
Before you can assign a value to an element like my.Name[0], you have to ensure that my.Name is referencing an allocated array, which means there is memory available for your elements.

Issue passing <List> object to multidimensional array

Issue trying to pass coordinates in to a multidimensional array. Errors thrown:
(1) at var newArray = item.To2dArray(); in GetInstructions() method:
List does not contain a definition for To2dArray and no extensible method To2dArray accepting a first argument of type ist
(2) at public partial class SiteMaster : MasterPage when the method public static Coords[,] To2dArray(this List<List<Coords>> list) is added
Extension method must be defined in non-generic static class
My list structure
public class Route
{
public string status_message { get; set; }
public string route_geometry { get; set; }
public int status { get; set; }
//route_instructions is what I'm interested in
public List<List<object>> route_instructions { get; set; }
}
public class Coords
{
public int Lat { get; set; }
public int Lon { get; set; }
public Coords(string a, string b)
{
this.Lat = Convert.ToInt32(a);
this.Lon = Convert.ToInt32(b);
}
}
List<Coords> Coordinates = new List<Coords>();
Code to deserialise JSON
private void GetInstructions()
{
string strurltest = String.Format("https://developers.onemap.sg/privateapi/routingsvc/route?start="+
startLat+","+ startLon +"&end="+ destinationLat +","+ destinationLon+"&"+
"routeType="+ transportType + "&token="+token);
WebRequest requestObjGet = WebRequest.Create(strurltest);
requestObjGet.Method = "GET";
HttpWebResponse responseObjGet = null;
responseObjGet = (HttpWebResponse)requestObjGet.GetResponse();
string strresulttest = null;
using (Stream stream = responseObjGet.GetResponseStream())
{
StreamReader sr = new StreamReader(stream);
strresulttest = sr.ReadToEnd();
sr.Close();
}
Route route = new JavaScriptSerializer().Deserialize<Route>(strresulttest);
route_geometry = route.route_geometry;
//display route instructions
foreach (var item in route.route_instructions)
{
var newArray = item.To2dArray();
System.Diagnostics.Debug.WriteLine(item[3]);
TextBox3.Text = TextBox3.Text + Environment.NewLine + item[9];
}
}
Code to convert list object to multidimensional array
public static Coords[,] To2dArray(this List<List<Coords>> list)
{
if (list.Count == 0 || list[0].Count == 0)
throw new ArgumentException("The list must have non-zero dimensions.");
var result = new Coords[list.Count, list[0].Count];
for (int i = 0; i < list.Count; i++)
{
for (int j = 0; j < list[i].Count; j++)
{
if (list[i].Count != list[0].Count)
throw new InvalidOperationException("The list cannot contain elements (lists) of different sizes.");
result[i, j] = list[i][j];
}
}
return result;
}
List object when printed is in this format: (when System.Diagnostics.Debug.WriteLine(item[3]); in GetInstructions()
1.315396,103.764419
1.314333,103.763455
1.312906,103.766496
1.312109,103.772234
You can only use a Method as Extension, if it is static and in an static class.
Your method To2dArray must be moved to an extra static class.
This is what the following message means:
Extension method must be defined in non-generic static class
The other problem is, that the signature of the method does not fit:
You are iterating through route.route_instructions so item is of type List<object> but your method needs List<List<Coords>>
foreach (var item in route.route_instructions)
{
var newArray = item.To2dArray();
///...

Using C# Reflection to assign collection of variable size to class properties

I have a destination class called Foo with the following properties:
public string Bar1 { get; set; }
public string Bar2 { get; set; }
public string Bar3 { get; set; }
public string Bar4 { get; set; }
public string Bar5 { get; set; }
public string Bar6 { get; set; }
I'm reading in a file that could have any number of "Bars" which I read into a collection called fileBars. I need to find out how to use Reflection to iterate over fileBars and assign the first one to Bar1, the second one to Bar2, etc.
I've tried several things I've found online, most recently playing with what's shown below, but I haven't had any luck. Can someone who is familiar with Reflection point me in the right direction?
var count = fileBars.Count();
var myType = Foo.GetType();
PropertyInfo[] barProperties = null;
for (var i = 0; i < count; i++)
{
barProperties[i] = myType.GetProperty("Bar" + i + 1);
}
I don't think you need to store the PropertyInfo objects in an array; you can just assign the values as you go:
var count = fileBars.Count();
var instance = new Foo();
for (var i = 1; i <= count; i++)
{
var property = typeof(Foo).GetProperty("Bar" + i);
if(property != null)
property.SetValue(instance, fileBars[i - 1];
else
// handle having too many bars to fit in Foo
}
You need to initialize barProperties:
PropertyInfo[] barProperties = new PropertyInfo[count];
To assign a value to the property, use SetValue:
barProperties[i].SetValue(Foo, fileBars[i] );
Unless you need to keep all the properties you find for later, you don't need the barProperties array:
var myType = foo.GetType();
int barCount = 0;
foreach(string barValue in fileBars)
{
barCount++;
var barProperty = myType.GetProperty("Bar" + barCount);
barProperty.SetValue(foo, barValue, null);
}

C# Trouble adding to a generic list

This is a follow up question from another post but that post was answered. I have a for loop that I want to add three items to a generic class and I'm not sure how to do that. How do I add those items?
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{
string[] split = List[i].Split('|');
// This is what i dont know how to do
// split[0] = Name, split[1] = SomeValue and split[3] = OrderNr
}
}
class Records
{
public static string Name { get; set; }
public static int SomeValue { get; set; }
public static int OrderNr { get; set; }
}
The first step is to associate the fields with instances of Records vs. the type itself. This is done by removing the static modifier
class Records
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNr { get; set; }
}
To actually create instances try the following
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records() {
Name = split[0]
SomeValue = Int32.Parse(split[1])
OrderNr = Int32.Parse(split[2])
};
Records.add(record);
}
This particular example uses an object initializer to combine the acts of creating the object and settings its fields. This could be expanded into the longer form as follows
for (int i = 0; i < ProxyList.Count; i++) {
string[] split = List[i].Split('|');
Records record = new Records();
record.Name = split[0];
record.SomeValue = Int32.Parse(split[1]);
record.OrderNr = Int32.Parse(split[2]);
Records.add(record);
}
The Int32.Parse method will throw an exception if the item in the original string wasn't a number. If this is a possibility (think bad input) then you'll want to wrap the creation of Records with a try / catch statement
Well for one thing, your properties must not be static. You want different data for each instance, right? So they need to be instance properties. Personally I'd also make the type immutable, but that's another matter:
class Record // Changed from Records; each object is only a single record...
{
public string Name { get; set; }
public int SomeValue { get; set; }
public int OrderNumber { get; set; }
}
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
List<Record> records = new List<Record>();
foreach (string line in lines)
{
string[] split = line.Split('|');
Record record = new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
};
records.Add(record);
}
}
As of C# 3 / .NET 3.5, a more idiomatic approach would be to use LINQ:
private static List<Record> ConvertRecords(IEnumerable<string> lines)
{
return (from line in lines
let split = line.Split('|')
select new Record {
Name = split[0],
SomeValue = int.Parse(split[1]),
OrderNumber = int.Parse(split[2]);
}).ToList();
}
}
... on the other hand, that's relatively advanced if you're really just starting to learn the language.
To be honest, Stack Overflow is better for asking specific questions than structured learning - I suggest you get hold of a good book, such as C# 4 in a Nutshell.
I'm not sure why you use static !!! but try this :
private static void TestResults()
{
List<Record> Records = new List<Record>();
for (int i = 0; i < ProxyList.Count; i++)
{;
string[] split = List[i].Split('|');
Records.Add(new Record() {Name = Namesplit[0] , SomeValue = split[1], OrderNr = split[3]}) ;
}
}

Parsing text file using C#

Looking for a good way to parse out of this text file, the values highlighted with the yellow boxes using C#. Each section is delineated by a TERM # which I forgot to highlight. Tried this:
string fileName = "ATMTerminalTotals.txt";
StreamReader sr = new StreamReader(fileName);
string[] delimiter = new string[] { " " };
while (!sr.EndOfStream)
{
string[] lines = sr.ReadLine().Split(delimiter, StringSplitOptions.RemoveEmptyEntries);
foreach (string line in lines)
{
Console.WriteLine(line);
}
}
Console.ReadLine();
Safe to say I am reading lines correctly and removing "white spaces." Although, as an amateur to programming, not sure of a valid way to accurately "know" that I am getting the values from this report that I need. Any advice?
i've tested this with a very simple program to parse the given file,
basically i've created two basic classes, a page class holding a collection of terminal report class (the tran type rows)
these rows maybe even can be represented as transaction and a billing class too
first parsed the data, setting the parameters needed and lastly just accessing the properties
just rushed it to be as simple as possible, no error handling etc... its just to give you a sense of how id start solving these kind of tasks, hope it helps
Adam
namespace TerminalTest
{
class Program
{
public class TerminalReport
{
public string Word { get; set; }
public int Denials { get; set; }
public int Approvals { get; set; }
public int Reversals { get; set; }
public double Amount { get; set; }
public int ON_US { get; set; }
public int Alphalink { get; set; }
public int Interchange { get; set; }
public int Surcharged { get; set; }
public static TerminalReport FromLine(string line)
{
TerminalReport report = new TerminalReport();
report.Word = line.Substring(0, 11);
line = line.Replace(report.Word, string.Empty).Trim();
string[] split = line.Split(' ');
int i = 0;
// transaction summary
report.Denials = int.Parse(split[i++]);
report.Approvals = int.Parse(split[i++]);
report.Reversals = int.Parse(split[i++]);
report.Amount = double.Parse(split[i++]);
// billing counts
report.ON_US = int.Parse(split[i++]);
report.Alphalink = int.Parse(split[i++]);
report.Interchange = int.Parse(split[i++]);
report.Surcharged = int.Parse(split[i++]);
return report;
}
}
public class TerminalPage
{
public int PageNumber { get; set; }
public double TotalSurcharges { get; set; }
public List<TerminalReport> Rows { get; set; }
public TerminalPage(int num)
{
PageNumber = num;
Rows = new List<TerminalReport>();
}
public int TotalDenials
{
get
{
return rows.Sum(r => r.Denials);
}
}
public int TotalApprovals
{
get
{
return Rows.Sum(r => r.Approvals;
}
}
public int TotalReversals
{
get
{
return Rows.Sum(r => r.Reversals;
}
}
public double TotalAmount
{
get
{
return Rows.Sum(r => r.Amount);
}
}
public int TotalON_US
{
get
{
return Rows.Sum(r => r.ON_US);
}
}
public int TotalAlphalink
{
get
{
return Rows.Sum(r => r.Alphalink);
}
}
public int TotalInterchange
{
get
{
return Rows.Sum(r => r.Interchange);
}
}
public int TotalSurcharged
{
get
{
return Rows.Sum(r => r.Surcharged);
}
}
}
private static string CleanString(string text)
{
return Regex.Replace(text, #"\s+", " ").Replace(",", string.Empty).Trim();
}
private static List<TerminalPage> ParseData(string filename)
{
using (StreamReader sr = new StreamReader(File.OpenRead(filename)))
{
List<TerminalPage> pages = new List<TerminalPage>();
int pageNumber = 1;
TerminalPage page = null;
bool parse = false;
while (!sr.EndOfStream)
{
string line = sr.ReadLine();
line = CleanString(line);
if (line.StartsWith("TRAN TYPE"))
{
// get rid of the ----- line
sr.ReadLine();
parse = true;
if (page != null)
{
pages.Add(page);
}
page = new TerminalPage(pageNumber++);
}
else if (line.StartsWith("="))
{
parse = false;
}
else if (line.StartsWith("TOTAL SURCHARGES:"))
{
line = line.Replace("TOTAL SURCHARGES:", string.Empty).Trim();
page.TotalSurcharges = double.Parse(line);
}
else if (parse)
{
TerminalReport r = TerminalReport.FromLine(line);
page.Rows.Add(r);
}
}
if (page != null)
{
pages.Add(page);
}
return pages;
}
}
static void Main(string[] args)
{
string filename = #"C:\bftransactionsp.txt";
List<TerminalPage> pages = ParseData(filename);
foreach (TerminalPage page in pages)
{
Console.WriteLine("TotalSurcharges: {0}", page.TotalSurcharges);
foreach (TerminalReport r in page.Rows)
Console.WriteLine(r.Approvals);
}
}
}
}
I'm not sure I'd split it by spaces actually.. the textfile looks like its split into columns. You might want to read like 10 chars (or whatever the width of the column is) at a time... and I'd parse the whole file into a dictionary so you get entries like
dict["WDL FRM CHK"]["# DENIALS"] = 236
then you can easily retrieve the values you want from there, and if you ever need more values in the future, you've got them.
Alternatively, you can use regexs. You can grab the first value with a regex like
^WDL FRM CHK\s+(?<denials>[0-9,]+)\s+(?<approvals>[0-9,]+)$
using
m.Groups["approvals"]
anyway I recommend you to wrap your StreamReader with using block:
using (StreamReader sr = new StreamReader(fileName))
{
// do stuff
}
Read more on MSDN
Given that it seems to have a standard, regular format, I would use regular expressions. You can check the starting code to figure out what row you're on, then an expression that will parse out the numbers and ignore whitespace will, very likely, be easier than handling it manually.
using System;
using System.Text.RegularExpressions;
namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Regex exp = new Regex(#"WDL FRM CHK(\s)+[1-9,]+(\s)+(?<approvals>[1-9,]+)(\s)+");
string str = "WDL FRM CHK 236 1,854 45,465 123 3";
Match match = exp.Match(str);
if (match.Success)
{
Console.WriteLine("Approvals: " + match.Groups["approvals"].Value);
}
Console.ReadLine();
}
}
}
Apdated from the following article to parse one of your numbers:
How to match a pattern by using regular expressions and Visual C#

Categories