I have this code:
invoiceSurcharges.Result = from surcharge in invoiceSurcharges.Result
select new ListInvoiceSurchargesGridByInvoice
{
};
Now, I would like to modify just one property of surcharge without having to assign each property of the object to the new one. It would be ideal if I could do something like:
invoiceSurcharges.Result = from surcharge in invoiceSurcharges.Result
select new ListInvoiceSurchargesGridByInvoice
{
...surcharge,
AssociatedInvoice = $"{surcharge.InvoiceSerial}-{surcharge.InvoiceYear}"
};
Is there any way I could do this in C#?
Add a copy constructor to ListInvoiceSurchargesGridByInvoice that copies all the properties from the sucharge object. You can still use property initializers to override specific properties. Consider making your objects immutable, and properties init-only, that helps avoid unintended mutation of your objects.
But an easier method is probably to use records, they are trivial to make immutable, and come with the with-expression to help creating copies with a minimal of boiler plate code:
public record ListInvoiceSurchargesGridByInvoice{
public string AssociatedInvoice { get; init; }
...
}
invoiceSurcharges.Result = from surcharge in invoiceSurcharges.Result
select surcharge with { AssociatedInvoice = $"{surcharge.InvoiceSerial}-{surcharge.InvoiceYear}"};
There are some caveats when using records with EntityFramework. If that is a concern I would recommend doing some further research.
Related
For this class setup.
public class X
{
public Y YInstance;
public X()
{
YInstance = new Y();
}
}
public class Y
{
public long Z;
}
I had this code.
var x = new X();
x.YInstance.Z = 1;
Resharper had a hint to use object initializer which transformed my code to this.
var x = new X { YInstance = { Z = 1 } };
I'm familiar with normal object initialization using the brackets to fill out properties but I'm not sure what this is doing. Looking at the IL it doesn't appear to be setting YInstance with a new anonymous class which was my first guess. That would also not be the same functionality as before which would weird for Resharper to suggest.
I'm just looking for a language feature keyword to look up or a simple explanation.
Syntax is arbitrary, strictly speaking, but in my view the way to think about it is that YInstance = { Z = 1 } has no new keyword, so it's not calling any constructors. However, the initializer part of the syntax is present, so it's merely applying the initializer to the properties of a (hopefully!) existing YInstance. YInstance exists in your case because you created it in your X constructor. Here's what would happen if you didn't.
Instead of "Set YInstance to this thing", it's "Set the properties of YInstance to those things".
= { ... } in this case means to apply that initializer to the existing value of a property.
Indicating that with = between the property name and the initializer braces may not seem ideally intuitive at first, but it is what it is and like any syntax, you learn to recognize it soon enough. You can do the same to initialize the items of collections that have already been created:
public class C {
public List<int> Items { get; } = new List<int>();
}
...
// This can't be assigning to Items, because it's read-only
var c = new C { Items = { 0, 1, 2 } };
One of the C# team members (if you mention his name, he will appear) once kindly took the time to comment on an answer to a question about the list initializer syntax. They kicked it around a lot, but this was the best option they came up with. There are a lot of considerations when it comes to adding syntax to a mature language. They lose a lot of sleep over making it as clear as possible to the programmer, but at the same time it has to be unambiguous to the compiler, it can't break existing code, etc. "Syntax is arbitrary" doesn't mean that the C# team makes arbitrary decisions.
I can't say why Resharper would object to your taking arms against a sea of curly braces. I like your original version better.
I am teaching myself C# and modern Windows programming in general and had a question about lists in C# that I haven't found an answer for. The reference book I am using seems to indicate that in C# before you can assign a variable to a list, you need to define a new variable for each item in the list and assign it's value.
I am trying to write a simple program that will let me write text notes, assign keywords to them, and them filter the resulting group of notes based on the keywords I select. From what I can figure out, a List seems the best mechanism in C# to do this since there will be an unknown number of notes. However, I am struggling with the idea of defining a unknown number of variable names ahead of time to store the notes in, to add to the List.
Am I looking at the wrong construct in C# for this, misunderstanding what is required to assign a variable value to a List, or lacking knowledge of some mechanism for auto-creating variables and variable names that can be leveraged as part of a list? Something else?
Sorry if this is too simple a question for SE crowd, but this seemed like the best place to ask.
A List<T> is a data structure that lets you store an unknown number of T, but you don't need variable names for the elements of the list - just for the list itself.
Is this what you need?
var notes = new List<string>()
{
"This is a note.",
"I am happy",
};
notes.Add("This is another happy note");
notes.AddRange(new [] { "Another happy notes", "This is also a note", });
var selected = notes.Where(n => n.Contains("happy")).ToList();
The values in selected are:
"I am happy", "This is another happy note", "Another happy notes"
I am not sure what exactly is your confusion. But it sounds like you are having issues in constructing class or using C# types. To keep it simple for now you can follow something in this manner.
// This represents individual note
public class Note
{
// Initialize keywords list in constructor
// in order to avoid Null reference exception.
public Note() {
Keywords = new List<string>();
}
public string Title { get; set; }
public string Content { get; set; }
public List<string> Keywords { get; set; }
}
// In main code, you can simply have List<Note> to hold collection of any no of notes.
// Also, when user adds a note you will create a new Note instance and add to collection.
List<Note> notes = new List<Note>();
Note newNote = new Note();
newNote.Title = "Note 1";
newNote.Content = "Note 1 Content";
newNote.Keywords.Add("Test1");
notes.Add(newNote);
I'm trying to store information in a block of anonymous values
//holds all info
var jobs = new { newJob, numBytes, requiredTime };
then take that information and place it into a list as a single element
//puts above info into a list
joblist.Add(Convert.ToString(jobs));
Console.WriteLine(joblist[0]); //testing purposes
now what I would like to do is be able to call joblist and take the value of example numBytes at position 4.
Is this possible? Or could someone help with an alternate way of doing this? Much thanks!
Create a named class. Then you can have a list of objects of that type and manipulate that list in any way you want.
Using classes is best-practice for what you are trying to do. By default you should consider storing structured data in an object model consisting of custom classes. There is another answer here which is proposing to use dynamic - this is valid and has its place, but it is more of a last resort solution. What you want is to play to the strength of C# which are rich classes and static typing. Anonymous types are also statically typed, but as you cannot name the type you cannot declare a statically typed list to hold them. You also can't use them as return types of methods.
The "normal" thing to do in C# would be to create a class to hold the information that you want to store. For example:
public class Job
{
public string Name { get; set; }
public int NumBytes { get; set; }
public DateTime RequiredTime { get; set; }
}
Then you can add these to a list:
var jobs = new List<Job>();
var aJob = new Job();
aJob.Name = "Job 1";
aJob.NumBytes = 123;
jobs.add(aJob);
Then you can access jobs by its index in the list:
var jobNumBytes = jobs[3].NumBytes;
One thing to note about C#, when you do:
new { newJob, numBytes, requiredTime };
The compiler, at build time, just creates you a strongly typed class (just like the Job class I created above) and generates a random name for it. It infers the property names and types from the variables that you are assigning to it. The created .exe or .dll actually does contain a class definition for this type, you just can't easily get to it from other places in your code. It isn't truly "dynamic". So using that syntax is usually just a lazy way of declaring a class that you just need for a moment. Usually just inside 1 method, then you don't need it any more. Creating a named class is usually what you want to do.
Actually I don't know exactly what you mean with "now what I would like to do is be able to call joblist and remove for example numBytes at position 4."
But I guess you just want to put the objects in a list and query for numBytes and maybe remove some elements.
With dynamics you can handle dynamic objects...
var jobs = new List<dynamic>();
for (int i = 0; i < 100; i++)
{
string newJob = "Job" + i;
int numBytes = i;
TimeSpan requiredTime = new TimeSpan(0,0,i);
//holds all info
var job = new { newJob, numBytes, requiredTime };
jobs.Add(job);
}
jobs.RemoveAll(p => p.numBytes > 50);
Instead of this, I agree with the comments below your question and would create a normal class which holds the properties you need and simply put instances of that into a list. Dynamics should be used only in very rare situations, and yours doesn't sound like it is extremely special.
I have a list with a lot of objects List<MyObjects> - Im iterating through this list and reading the objects. Thats all fine. I just relized now, what it would be awesome if I could add 1 more special value to this List - not an Object, just 1 value of something (a string).
I could now create a class like
class Needless
{
public List<MyObjects> MyList { get; set; }
public string MyValue { get; set; }
}
but Im trying to avoid that. I just really need 1 string with an input every List<MyObjects> Any ideas?
Tuple<string, List<MyObject>> is an option. However, if you are going to use this pairing a lot, I would advise creating a custom class for it to be more explicit - either like you have done, or by deriving List<MyObject> and adding the string as a property.
If you are working "in scope" you could always make anonymous types:
var t = new { TheString = "", TheList = new List<MyObject>() };
var list = t.TheList;
var s = t.TheString;
But this only really has benefit in the scope of a method. The compiler can give IntelliSense for this and it is strongly-typed at compile time.
Or if you really want to go all out, use ExpandoObject from System.Dynamic:
var expando = new ExpandoObject();
expando.List = new List<MyObject>();
expando.TheString = "";
This is typed in-line without any IntelliSense support, and will invoke the DLR. ExpandoObject simply uses an IDictionary<string, object> under the hood, so...
var dict = (IDictionary<string, object>)expando;
...is valid.
The last option is a little tongue-in-cheek. It'll work, but the development experience against it isn't ideal compared to other options. That said, we use ExpandoObject in our test code, but I can't remember why. One can only hope the reasoning was sound, but it was likely a developer getting giddy with new toys...
you can inherit the List and simply add your property, it's a bit cleaner than composite the List inside another class
You could extend a List implementation with your Needless class. That way you can still treat your list as a list.
I'm very new with c#, and was previously attempting to ignore classes and build my small program structurally more similar to PHP. After reaching a road block, I'm trying to start over and approach the problem properly OO. I'm taking a long file, and in a loop, every time certain conditions are met, I want to make a new object. How can I have it create a new object, without having to specify a unique name?
Referral ObjectName = new Referral(string, string, int);
Secondly, once this is done, and the strings & int set their appropriate object properties, how can i unique-ify the class by one property, and then sort the class by another?
I'm sorry if these are basic questions, I have spent a large, large amount of time first trying to figure it out on my own with google, and a textbook. If only C# would allow multi-dimensional arrays with different types!
Thank you so much!
PS. I do mean to extract a list of unique objects.
All these answers, while helpful, seem to involve creating a shadow set of IEnumerables. Is there no way to do this with the class itself?
Trying the first solution, provided by Earwicker, adding each object to a List from within the loop, when I try to Write a property of the element to the console, i get the ClassName+Referral. What could I be doing wrong?--solved. still needed .property
still working. . .
C# does allow untyped arrays. All objects are derived ultimately from object, so you use an array or container of objects. But it's rarely necessary. How many types of object do you have?
Within the loop block, you can create an object exactly as you do in that line of code (except with the syntax fixed), and it will be a new object each time around the loop. To keep all the objects available outside the loop, you would add it to a container:
List<Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals.Add(r);
Suppose Referral has a numeric property called Cost.
referrals.Sort((l, r) => l.Cost - r.Cost);
That sorts by the cost.
For ensuring uniqueness by some key, you may find it easier to pick a more suitable container.
Dictionary<string, Referral> referrals = new List<Referral>();
// in the loop:
Referral r = new Referral(str1, str2, num1);
referrals[str1] = r;
This stores the referral in a "slot" named after the value of str1. Duplicates will overwrite each other silently.
First, you're going to need to spend some time familiarizing yourself with the basics of the language to be productive. I recommend you take a little time to read up on C# before getting in too deep - otherwise you'll spend a lot of your time spinning your wheels - or reinventing them :)
But here's some info to get you started.
Typically, in C# you create classes to represent elements of your program - including those that are used to represent information (data) that your program intends to manipulate. You should really consider using one, as it will make data manipulation clearer and more manageable. I would advise avoiding untyped, multi-dimensions array structures as some may suggest, as these rapidly become very difficult to work with.
You can easily create a Referall class in C# using automatic properties and a simple constructor:
public class Referall
{
// these should be named in line with what they represent...
public string FirstString { get; set; }
public string AnotherString { get; set; }
public int SomeValue { get; set; }
public Referall( string first, string another, int value )
{
FirstString = first;
AnotherString = another;
SomeValue = value;
}
}
You can add these to a dictionary as you create them - the dictionary can be keyed by which ever property is unique. Dictionaries allow you to store objects based on a unique key:
Dictionary<string,Referall> dict = new Dictionary<string,Referall>();
As you process items, you can add them to the dictionary:
Referall ref = new Referall( v1, v2, v3 );
// add to the dictionary, keying on FirstString...
dict.Add( ref.FirstString, ref );
If you need to sort items in the dictionary when you're done, you can use LINQ in C# 3.0:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString );
You can sort by multiple dimension using ThenBy() as well:
IEnumerable<Referall> sortedResults =
dict.Values.OrderBy( x => x.AnotherString )
.ThenBy( x => x.SomeValue );
List<Referral> referrals = new List<Referral>();
for (...)
{
referrals.Add(new Referral(string1, string2, number1));
}
Then, if you're using Linq (which I highly suggest), you can do this:
IEnumerable<Referral> sorted = referrals.OrderBy(x => x.string1).ThenBy(x => x.string2);
Otherwise, you can use the Sort() method on List<Referral>.
You can create an object without a reference, but you won't have any access to it later:
new Referral(string, string, int);
If you wish to put them in an array/list, these different types need to have a common base class. This is called polimorfism, which is a very important concept in OO programming.
You cannot ignore classes while using c#. Don't resist the change!
Do you really not need to create a class here? Do you really not need to give it a name? C# does allow loose typing, but type safety is a good thing.
I don't fully understand what you're trying to do. But maybe LINQ is what you're looking for. There's tons of documentation around, but as a quick 'teaser' have a look at the 101 Linq samples on MSDN
C# includes a wonderful feature called "iterator blocks". What you want to do is use the yield keyword to create an Enumerable of your Referal object, something like this (not that I'm making the file format and property names up, because you didn't share that):
public class Referral
{
public Guid id { get; private set; } // "uniquify"
public int ReferringId { get; set; }
public string ReferrerText { get; set; }
public string ReferrerDescription { get; set; }
private Referral()
{
id = new Guid();
}
private Referral(string Text, string Description, int ReferringId) : this()
{
this.ReferrerText = Text;
this.ReferrerDescription = Description;
this.ReferringId = ReferringId;
}
public static IEnumerable<Referral> GetReferrals(string fileName)
{
using (var rdr = new StreamReader(fileName))
{
var next = new Referrer();
int state = 0;
string line;
while ( (line = rdr.ReadLine() ) != null)
{
switch (state)
{
case 0:
next.ReferrerText = line;
state = 1;
break;
case 1:
next.ReferrerDescription = line;
state = 2;
break;
case 2:
next.ReferringId = int.Parse(line);
yield return next;
next = new Referral();
state = 0;
break;
}
}
}
}
}
Now you want to sort the referrals and presumable enumerate over them for some purpose. You can do that easily like this:
foreach (var referral in Referral.GetReferrals(#"C:\referralfile.txt").OrderBy( r => r.Text ) )
{
OutputReferral(referral);
}