How to set multiple values of properties inside an object in C#? - c#

Please tell me how to add multiple properties inside an single object.
like- if there is a class having 5 variables defined with get and set.
I want to add like 2 values for each variable through a single object of that class like
class Info{
int count{get , set,};
string name{get , set,};
string Dept {get , set,};
string Address {get , set,};
long contact {get , set,};
info obj =new Info();
/* Now after this I want to take 2 rows like
in first row I want to set it's values through a single object
Count=1,name="Robert",Dept="Computer",Address="India",Contact=434343
in row 2nd row
Count=1,name="Robbin",Dept="Electronic",Address="Colombo",Contact=54545
*/
}
/// Now please explain me how to set like above two rows values inside one object.. ///

I think what you're looking for is inline object initialization: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/how-to-initialize-objects-by-using-an-object-initializer
You can write it on a single line but the code would look better if you break it into multiple lines:
Info infoObj = new Info
{
Count = 1,
Name = "Robert",
Dept = "Computer",
Address = "India",
Contact = 434343
};

If what you mean is initializing a class with set properties, look at Peter Sandor's answer.
if you're looking to declare a class with a set of fields that'll be filled with values upon initialization without giving them values (aka. default values), then this might help:
class Info
{
public int count = 5;
pubic string name = "Robert"
}
Please note that these are fields and not properties though, if you'd like to do the same with properties instead of fields, i'd suggest doing this with propfull:
private int count = 5;
public int Count
{
get { return count; }
set { count = value; }
}
Hope this helps!

Instead of creating an instance of the Info class, make a List of Info:
List<Info> aSingleObj = new List<Info>();
Now you can add as many things to the single object:
aSingleObj.add(new Info { Count = 1, name = "Robert", Dept = "Computer", Address = "India", contact = "434343" });
aSingleObj.add(new Info { Count = 1, name = "Robbin", Dept = "Electronic", Address = "Colombo", contact = "54545" });
To distinguish between them, and print the output, do:
Console.WriteLine($"First row: Count = {aSingleObj[0].Count}, Name = {aSingleObj[0].name}, Department: {aSingleObj[0].Dept}, Address = {aSingleObj[0].Address}, Contact = {aSingleObj[0].contact}");
and for second row:
Console.WriteLine($"Second row: Count = {aSingleObj[1].Count}, Name = {aSingleObj[1].name}, Department: {aSingleObj[1].Dept}, Address = {aSingleObj[1].Address}, Contact = {aSingleObj[1].contact}");

Related

Sorting List Array based on an index of array

I want to sort a List Array on the basis of an array item.
I have a List Array of Strings as below:
List<String>[] MyProjects = new List<String>[20];
Through a loop, I have added five strings
(Id, Name, StartDate, EndDate, Status)
to each of the 20 projects from another detailed List source.
for(int i = 0; i<20; i++){
MyProjects[i].Add(DetailedProjectList.Id.ToString());
MyProjects[i].Add(DetailedProjectList.Name);
MyProjects[i].Add(DetailedProjectList.StartDate);
MyProjects[i].Add(DetailedProjectList.EndDate);
MyProjects[i].Add(DetailedProjectList.Status)}
The Status values are
"Slow", "Normal", "Fast", "Suspended" and "" for unknown status.
Based on Status, I want to sort MyProject List Array.
What I have done is that I have created another List as below
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
I tried as below to sort, however unsuccessful.
MyProjects = MyProjects.OrderBy(x => sortProjectsBy.IndexOf(4));
Can anyone hint in the right direction. Thanks.
I suggest you to create class Project and then add all the fields inside it you need. It's much nicer and scalable in the future. Then create a List or an Array of projects and use the OrderBy() function to sort based on the field you want.
List<Project> projects = new List<>();
// Fill the list...
projects.OrderBy(project => project.Status);
The field Status has to be a primitive type or needs to implement the interface IComparable in order for the sorting to work. I suggest you add an enum for Status with int values.
First consider maybe to use Enum for status and put it in a different file lite (utils or something) - better to work like that.
enum Status {"Slow"=1, "Normal", "Fast", "", "Suspend"}
Now about the filtering you want to achieve do it like this (you need to tell which attribute of x you are referring to. In this case is status)
MyProjects = MyProjects.OrderBy(x => x.status == enum.Suspend);
Read about enums :
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/enum
Read about lambda expressions :
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/lambda-expressions
First of all, storing project details as List is not adivisable. You need to create a Custom Class to represent them.
For example,
public class DetailedProjectList
{
public string Name {get;set;}
public eStatus Status {get;set;}
// rest of properties
}
Then You can use
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
For example
List<string> sortProjectsBy = new List<string>(){"Slow", "Normal", "Fast", "", "Suspended"};
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status="Fast"},
new DetailedProjectList{Name="abc2", Status="Normal"},
new DetailedProjectList{Name="abc3", Status="Slow"},
};
var result = MyProjects.OrderBy(x=> sortProjectsBy.IndexOf(x.Status));
Output
abc3 Slow
abc2 Normal
abc1 Fast
A better approach thought would be to use Enum to represent Status.
public enum eStatus
{
Slow,
Normal,
Fast,
Unknown,
Suspended
}
Then your code can be simplified as
var MyProjects= new List<DetailedProjectList>{
new DetailedProjectList{Name="abc1", Status=eStatus.Fast},
new DetailedProjectList{Name="abc2", Status=eStatus.Normal},
new DetailedProjectList{Name="abc3", Status=eStatus.Slow},
};
var result = MyProjects.OrderBy(x=> x.Status);
Ok so you have a collection of 20 items. Based on them you need to create a list of strings(20 DetailedProjectList items).
What you can do to solve your problem is to SORT YOUR COLLECTION before you create your list of strings. In this way your list of strings will be sorted.
But your code is not optimal at all. So you should concider optimization on many levels.
Lets say you have ProjectDetail class as follow:
private class ProjectDetail
{
public int Id {get;set;}
public string Name {get;set;}
DateTime StartDate {get;set;} = DateTime.Now;
DateTime EndDate {get;set;} = DateTime.Now;
public string Status {get;set;}
public string toString => $"{Id} - {Name} - {StartDate} - {EndDate} - {Status}";
}
Notice that I have added a toString attribute to make things easier, and I also have added default values.
Then your program could be like:
static void Main(string[] args)
{
var projectDetails = MockProjectItems();
Console.WriteLine("Before sortig:");
foreach (var item in projectDetails)
{
Console.WriteLine(item.toString);
}
var myProjects = projectDetails.OrderBy(p => p.Status).Select(p => p.toString);
Console.WriteLine("\n\nAfter sorting:");
foreach (var item in myProjects)
{
Console.WriteLine(item);
}
}
where the helper method is
private static List<ProjectDetail> MockProjectItems()
{
var items = new List<ProjectDetail>(20);
for(int i = 0; i < 20 ; i += 4){
items.Add(new ProjectDetail{Id = i, Name = "RandomName "+i, Status = "Slow"});
items.Add(new ProjectDetail{Id = i+1, Name = "RandomName "+(i+1), Status = "Normal"});
items.Add(new ProjectDetail{Id = i+2, Name = "RandomName "+(i+2), Status = "Fast"});
items.Add(new ProjectDetail{Id = i+3, Name = "RandomName "+(i+3), Status = "Suspended"});
}
return items;
}
Then your program should print the following:

Setting the orderLine property on an item when updating an invoice

My problem is that after creating an invoice, I can never get new line items to reference their corresponding sales order line item.
I have been generating invoices via SuiteTalk. When I initially create an invoice, I empty the lineItemList and add back in the items I need. I make sure the orderLine property matches the sales order line item line number. This works great.
But when I try and update the invoice with additional line items, I can never get the new items to retain their orderLine property. The orderLine property is used for the "Invoiced" column on the Sales Order.
In order to get the referencing to be correct, I need to delete the invoice and create it again with all of the line items I need.
Does anyone know if what I am trying to do is possible?
In this example, I use this CreateInvoice function to create the invoice from scratch and add it to NetSuite. Everything works as expected.
public void CreateInvoice(SalesOrder salesOrder) {
Invoice brandNewInvoice = new Invoice() {
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
entity = salesOrder.entity,
tranDate = endDate,
tranDateSpecified = true,
startDate = startDate,
startDateSpecified = true,
endDate = endDate,
endDateSpecified = true,
itemList = new InvoiceItemList(),
};
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.add(brandNewInvoice);
}
In this example, the invoice is already created and so I get it from NetSuite and then replace the existing itemList with a new one. After the update, the invoice will now have NO orderLine property for any of the line items. The invoice also loses its "Created From" field because there are no line items with the orderLine property set.
public void UpdateInvoice(SalesOrder salesOrder, String invoiceInternalId) {
Invoice invoice = GetNetSuiteInvoice(invoiceInternalId);
invoice.itemList.item = GetInvoiceItemList(salesOrder); //see the function shown further down
netSuiteService.update(invoice);
}
this is the function used to create the itemList:
public InvoiceItem[] GetInvoiceItemList(SalesOrder salesOrder) {
InvoiceItem[] invoiceItemList = new InvoiceItem[salesOrder.itemList.item.Length];
for (int i = 0; i < salesOrder.itemList.item.Length; i++) {
SalesOrderItem soItem = salesOrder.itemList.item[i];
double quantity = 1;
invoiceItemList[i] = new InvoiceItem() {
item = new RecordRef() {
internalId = soItem.item.internalId,
name = soItem.item.name,
},
amount = quantity * Double.Parse(soItem.rate),
amountSpecified = true,
quantity = quantity,
quantitySpecified = true,
price = new RecordRef() {
internalId = soItem.price.internalId,
name = soItem.price.name,
},
rate = soItem.rate,
orderLine = soItem.line, //this will establish the link between the invoice and the sales order
orderLineSpecified = true,
taxRate1 = soItem.taxRate1,
taxRate1Specified = true,
};
}
return invoiceItemList;
}
Actually what you are looking for is the intialize operation. You need to use initialize in order for Netsuite to properly fill in the created from and orderline props. From the NS Help there is a C# example of creating a Cash Sale:
private void Initialize()
{
this.login(true);
InitializeRef ref1 = new InitializeRef();
ref1.type = InitializeRefType.salesOrder;
//internal id of the sales order to be converted to cash sale
ref1.internalId = "792";
ref1.typeSpecified = true;
InitializeRecord rec = new InitializeRecord();
rec.type = InitializeType.cashSale;
rec.reference = ref1;
ReadResponse read1 = _service.initialize(rec);
}
This is normal, when transforming a transaction to another transaction (e.g. SO to Inv, PO to IR). When you transform, most of the information from the source transaction will be carried over. Like what you are doing which is creating an Invoice from Sales Order(Base on your code below).
createdFrom = new RecordRef() {
internalId = salesOrder.internalId,
},
You don't need to get the line item information from the Sales Order and put it in the Invoice because it will be pre-populated once you create it form Sales Oder(unless you need to change a value of a line item column).
One behavior of a transformed record(Invoice in your case), if you remove a line item from the Invoice you will lose the link to the Sales order(orderLine) and if you remove all the line item you will totally lose the link between the two transactions (createdfrom). This is what you are experiencing. orderLine/createdFrom is a field populated by the system, it looks like you are populating it but you are not.

How can I select a number and value from an enum in C#?

I have just changed my code so that now it stores some data in an enum instead of in a SQL Server table.
Here's the enum:
public enum ContentTypes : int
{
Article = 0,
Menu = 1,
ContentBlock = 3
}
I was running the following code:
var contentTypes =
(
from contentType in this._contentTypeService.GetContentTypes()
select new
{
id = contentType.ContentTypeId,
name = contentType.Name
}
);
How can I change this so that instead of taking the data from the content service it just queries the enum to data for contentTypes?
I think what you want is this
var contentTypes =
from value in Enum.GetValues(typeof(ContentTypes)).Cast<int>()
select new
{
id = value,
name = Enum.GetName(typeof(ContentTypes), value)
};
pswg might be right, but I am thinking you want something like this?
Here is code more direct to your question:
select new
{
id = (int)contentType,
name = contentType.ToString()
}
You can get the integer id simply by casting to an int and get the name of it by using its ToString (which may or may not be implicit here)

Column headers in CSV using fileHelpers library?

Is there a built-in field attribute in the FileHelper library which will add a header row in the final generated CSV?
I have Googled and didn't find much info on it. Currently I have this:
DelimitedFileEngine _engine = new DelimitedFileEngine(T);
_engine.WriteStream
(HttpContext.Current.Response.Output, dataSource, int.MaxValue);
It works, but without a header.
I'm thinking of having an attribute like FieldTitleAttribute and using this as a column header.
So, my question is at which point do I check the attribute and insert header columns? Has anyone done something similar before?
I would like to get the headers inserted and use custom text different from the actual field name just by having an attribute on each member of the object:
[FieldTitleAttribute("Custom Title")]
private string Name
and maybe an option to tell the engine to insert the header when it's generated.
So when WriteStream or WriteString is called, the header row will be inserted with custom titles.
I have found a couple of Events for DelimitedFileEngine, but not what's the best way to detect if the current record is the first row and how to insert a row before this.
I know this is an old question, but here is an answer that works for v2.9.9
FileHelperEngine<Person> engine = new FileHelperEngine<Person>();
engine.HeaderText = engine.GetFileHeader();
Here's some code that'll do it: https://gist.github.com/1391429
To use it, you must decorate your fields with [FieldOrder] (a good FileHelpers practice anyway). Usage:
[DelimitedRecord(","), IgnoreFirst(1)]
public class Person
{
// Must specify FieldOrder too
[FieldOrder(1), FieldTitle("Name")]
string name;
[FieldOrder(2), FieldTitle("Age")]
int age;
}
...
var engine = new FileHelperEngine<Person>
{
HeaderText = typeof(Person).GetCsvHeader()
};
...
engine.WriteFile(#"C:\people.csv", people);
But support for this really needs to be added within FileHelpers itself. I can think of a few design questions off the top of my head that would need answering before it could be implemented:
What happens when reading a file? Afaik FileHelpers is currently all based on ordinal column position and ignores column names... but if we now have [FieldHeader] attributes everywhere then should we also try matching properties with column names in the file? Should you throw an exception if they don't match? What happens if the ordinal position doesn't agree with the column name?
When reading as a data table, should you use A) the field name (current design), or B) the source file column name, or C) the FieldTitle attribute?
I don't know if you still need this, but here is the way FileHelper is working :
To include headers of columns, you need to define a string with headers delimited the same way as your file.
For example with '|' as delimiter :
public const string HeaderLine = #"COLUMN1|COLUMN2|COLUMN3|...";
Then, when calling your engine :
DelimitedFileEngine _engine = new DelimitedFileEngine<T> { HeaderText = HeaderLine };
If you don't want to write the headers, just don't set the HeaderText attribute on the engine.
List<MyClass> myList = new List<MyClass>();
FileHelperEngine engine = new FileHelperEngine(typeof(MyClass));
String[] fieldNames = Array.ConvertAll<FieldInfo, String>(typeof(MyClass).GetFields(), delegate(FieldInfo fo) { return fo.Name; });
engine.HeaderText = String.Join(";", fieldNames);
engine.WriteFile(MapPath("MyClass.csv"), myList);
Just to include a more complete example, which would have saved me some time, for version 3.4.1 of the FileHelpers NuGet package....
Given
[DelimitedRecord(",")]
public class Person
{
[FieldCaption("First")]
public string FirstName { get; set; }
[FieldCaption("Last")]
public string LastName { get; set; }
public int Age { get; set; }
}
and this code to create it
static void Main(string[] args)
{
var people = new List<Person>();
people.Add(new Person() { FirstName = "James", LastName = "Bond", Age = 38 });
people.Add(new Person() { FirstName = "George", LastName = "Washington", Age = 43 });
people.Add(new Person() { FirstName = "Robert", LastName = "Redford", Age = 28 });
CreatePeopleFile(people);
}
private static void CreatePeopleFile(List<Person> people)
{
var engine = new FileHelperEngine<Person>();
using (var fs = File.Create(#"c:\temp\people.csv"))
using (var sw = new StreamWriter(fs))
{
engine.HeaderText = engine.GetFileHeader();
engine.WriteStream(sw, people);
sw.Flush();
}
}
You get this
First,Last,Age
James,Bond,38
George,Washington,43
Robert,Redford,28
I found that you can use the FileHelperAsyncEngine to accomplish this. Assuming your data is a list called "output" of type "outputData", then you can write code that looks like this:
FileHelperAsyncEngine outEngine = new FileHelperAsyncEngine(typeof(outputData));
outEngine.HeaderText = "Header1, Header2, Header3";
outEngine.BeginWriteFile(outputfile);
foreach (outputData line in output){
outEngine.WriteNext(line);
}
outEngine.Close();
You can simply use FileHelper's GetFileHeader function from base class
var engine = new FileHelperEngine<ExportType>();
engine.HeaderText = engine.GetFileHeader();
engine.WriteFile(exportFile, exportData);

Modify Dictionary Value is possible.What is the right approach?

I have dictionary that is populated and I have no control of.
I need to modify the value how can I do that?
I have put a noddy example together to explain the problem
class Program
{
static void Main(string[] args)
{
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
CustomerOrderDictionary.Add(new Customer { Id = 1, FullName = "Jo Bloogs" },3);
CustomerOrderDictionary.Add(new Customer { Id = 2, FullName = "Rob Smith" },5);
//now I decide to increase the quantity but cannot do the below as value has no setter
foreach (var pair in CustomerOrderDictionary)
{
if(pair.Key.Id==1)
{
pair.Value = 4;///ERROR HERE
}
}
}
}
public class Customer
{
public int Id { get; set; }
public string FullName { get; set; }
}
Any suggestions?
Thanks a lot
I suggest you work out which keys need modifying first, and then iterate over those modifications. Otherwise you'll end up modifying a collection while you're iterating over it, which will throw an exception. So for example:
// The ToList() call here is important, so that we evaluate all of the query
// *before* we start modifying the dictionary
var keysToModify = CustomerOrderDictionary.Keys
.Where(k => k.Id == 1)
.ToList();
foreach (var key in keysToModify)
{
CustomerOrderDictionary[key] = 4;
}
The problem here is that pair is typed to KeyValuePair which is a readonly object and can't be modified. Additionally the KeyValuePair collection is a way of viewing the contents of the dictionary (not changing it).
What you want to do here is just modify the dictionary directly. The Key in the KeyValuePair can be used to update the same entry in the dictionary.
if(pair.Key.Id==1) {
CustomerOrderDictionary[pair.Key] = 4;
}
EDIT
As Jon pointed out the assignment will invalidate the iterator. The simplest, but ineffecient route, is to copy the enumerator at the start of the loop.
foreach (var pair in CustomerOrderDictionary.ToList())
Here is an alternate approach
1) Create a new class
// wrapper class to allow me to edit a dictionary
public class IntWrapper
{
public int OrderCount{ get; set; }
}
2) Change this declaration
Dictionary<Customer, IntWrapper> CustomerOrderDictionary = new Dictionary<Customer, IntWrapper>();
3) Assign your variable
pair.Value.OrderCount = 4;
foreach (Customer customer in customers.Keys)
{
if ( customer.Id == 1 )
customers[ customer ] = 4;
}
CustomerOrderDictionary[1] = 4;
Here's one way to do that (just the assigning a value part..):
CustomerOrderDictionary[new Customer { Id = 1, FullName = "Jo Bloogs" }]=4
Notice that "1" is not a key in your dictionary. a Customer is, so you'll have to use that.
Notice also that Customer Should implement IEquatable as explained here
Ok, in your example you're effectively just finding the entry for the Customer object with Id = 1 and updating the associated value. In practice, I think that your code will likely be able to obtain a reference to your intended Customer object prior to updating the associated value in the dictionary. If that is the case, then there's no need for a loop.
Below is a very simple example where a loop is not needed because your code already has a reference to the customer1 variable. While my example is overly simplified, the concept is that you could potentially obtain a reference to your desired Customer object through some means other than iterating over the dictionary.
static void Main(string[] args)
{
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" };
Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" };
CustomerOrderDictionary.Add(customer1, 3);
CustomerOrderDictionary.Add(customer2, 5);
// you already have a reference to customer1, so just use the accessor on the dictionary to update the value
CustomerOrderDictionary[customer1]++;
}
If you need to perform some kind of update on multiple Customer objects based on some other criteria, then you might need a loop. The following example assumes that you'll have some collection other than the dictionary that stores your Customer objects, and that you can use that collection of Customer objects to identify the ones whose associated value in the dictionary need to be updated.
static void Main(string[] args)
{
// presumably you will have a separate collection of all your Customer objects somewhere
List<Customer> customers = new List<Customer>();
Customer customer1 = new Customer { Id = 1, FullName = "Jo Bloogs" };
Customer customer2 = new Customer { Id = 2, FullName = "Rob Smith" };
Customer customer3 = new Customer { Id = 3, FullName = "Rob Zombie" };
customers.Add(customer1);
customers.Add(customer2);
customers.Add(customer3);
Dictionary<Customer, int> CustomerOrderDictionary = new Dictionary<Customer, int>();
CustomerOrderDictionary.Add(customer1, 3);
CustomerOrderDictionary.Add(customer2, 5);
// let's just say that we're going to update the value for any customers whose name starts with "Rob"
// use the separate list of Customer objects for the iteration,
// because you would not be allowed to modify the dictionary if you iterate over the dictionary directly
foreach (var customer in customers.Where(c => c.FullName.StartsWith("Rob")))
{
// the dictionary may or may not contain an entry for every Customer in the list, so use TryGetValue
int value;
if (CustomerOrderDictionary.TryGetValue(customer, out value))
// if an entry is found for this customer, then increment the value of that entry by 1
CustomerOrderDictionary[customer] = value + 1;
else
// if there is no entry in the dictionary for this Customer, let's add one just for the heck of it
CustomerOrderDictionary.Add(customer, 1);
}
}
If this is not the case and the only source of Customer objects that you have available is the dictionary itself, then you'll need to perform some kind of cloning/copying of those objects out to a separate list/array prior to iterating over the dictionary for modification. See Jon Skeet's answer for this case; he suggests using a Where filter on the dictionary's Keys property and uses the ToList method to create a separate List<Customer> instance for the purpose of iteration.

Categories

Resources