I would like to rearrange my properties inside a object initializer, by manually defining the new position. I found this Question but the first method only sorts the properties alphabetically, the other uses a different extension method.
new Student { StudentID = 2, Nationality = Nationalities.Austrian, StudentName = "Peter", Age = 21 }
A line like the above, I would like to rearrange using ReSharper or a Built-In Feature to this:
new Student { StudentID = 2, StudentName = "Peter", Age = 21, Nationality = Nationalities.Austrian }
Is there any possibility to achieve this?
Related
When using Kotlin, one could use apply to set multiple properties of an existing object and keeping the code cleaner, for example instead of:
person.firstName = "John"
person.lastName = "Doe"
person.phone = "123 456 789"
We can use:
person.apply {
firstName = "John"
lastName = "Doe"
phone = "123 456 789"
}
Is there an equivalent to the apply in C#?
The closest to this is the using but it can't be used this way as far as I know.
Edit: I know of object initializer in C#, but I'm actually looking for something that can be done for existing objects (for example an object fetched from the database).
Try this.... https://dev.to/amay077/kotlins-scope-functions-in-c-pbn
Code pasted below for convenience, but the above link is the source...
static class ObjectExtensions
{
// Kotlin: fun <T, R> T.let(block: (T) -> R): R
public static R Let<T, R>(this T self, Func<T, R> block)
{
return block(self);
}
// Kotlin: fun <T> T.also(block: (T) -> Unit): T
public static T Also<T>(this T self, Action<T> block)
{
block(self);
return self;
}
}
Can be used like this....
var model = new MyModel().Also(m => {
m.Initialize();
m.Load(path);
});
You can use it in this way with object initializers:
var person = new Person
{
FirstName = "John",
LastName = "Doe",
Phone = "123 456 789"
};
Or with a constructor:
var person = new Person("John", "Doe", "123 456 789");
Your class would have to look like this for the constructor option:
class Person
{
public Person(string firstName, string lastName, string phone)
{
FirstName = firstName;
LastName = lastName;
Phone = phone;
}
public string FirstName { get;set; }
public string LastName { get;set; }
public string Phone { get;set; }
}
There is currently no support in C# (version 8) for grouped multi-property assignment outside of object initialization.
Similar support exists in VB.NET and has been proposed for C# 9.
Little bit of historical context
In Visual Basic.NET there is similar statement - With:
With person
.FirstName = "John"
.LastName = "Doe"
.Phone = "123 456 789"
End With
This one was carried from Visual Basic 6 for backward compatibility (previous, non .NET Version of language).
C# team (Anders Heilsberg himself told the story somewhere) argued that With statement decreases code readability and did not want to introduce it in the language. From what I have seen With statements can be nested and can creating quite a confusion of what is going on.
As many others have already mentioned, there is object initializer syntax that is quite similar:
var person = new Person
{
firstName = "John",
lastName = "Doe",
phone = "123 456 789"
};
Future - C# 9
As pointed out in another (deleted) answer, there is an open proposal for records and With expression, to be added in C# 9:
person with { firstName = "John", lastName = "Doe", phone = "123 456 789" };
Bonus Tip
However, most important advice I can give you, to avoid annoying fellow C# developer who might work on your code - we don't use camelCase in C# for public properties and methods, because C# is not Java. We use PascalCase! :)
With an object initializer:
var person = new Person
{
firstName = "John",
lastName = "Doe",
phone = "123 456 789"
};
After you already have the object, you can give yourself a short variable:
var p = person;
p.firstName = "Jane";
p.lastName = "Smith";
p.phone = "987 654 321";
//later:
Console.WriteLine(person.lastName); //will output "Smith"
which is less still less code than the apply option.
Object initializers allow you to do that but only at instanciation of an object.
Like
var person = new Person
{
FirstName = "John",
LastName = "Doe",
Phone = "123 456 789"
}
After copying Apply into several projects, i made a nuget package.
dotnet add package Object.Extensions.ScopeFunction
It offers extension methods Apply, ApplyForEach and Map (which lets you override return).
var permissionsMissingTestContext = new TestContext
{
Users = GetStandardUsers().ApplyForEach(x => x.Permissions = new Permission[0]),
SecurityPolicy = GetStandardSecurityPolicy().Apply(x => x.ShowWarningWhenPermissionsMissing = true),
AnonymousPageUrl = GetStandardConfig().Map(x => new Url(x.PermissionsMissingScreenUrl)),
Timeout = GetTestTimeout()?.Map(x => TimeSpan.FromSeconds(x)) ?? TimeSpan.FromSeconds(30)
}
Nuget
I'm programming in C# and I want to instantiate lots of new objects to my application, all of the same type, but with different values for their properties. Example:
Student student1 = new Student();
student1.Name = "James";
student1.Age = 19;
student1.City = "Los Angeles";
Student student2 = new Student();
student2.Name = "Karen";
student2.Age = 20;
student2.City = "San Diego";
Student student3 = new Student();
student3.Name = "Bob";
student3.Age = 20;
student3.City = "Dallas";
This way of coding seems really wrong to me because what if I didn't need 3, but 500 students? What would be the best way to do it then?
I tried to use a for loop for this but that doesn't work because the property values differ.
What is the most efficient way to do this?
Thanks in advance.
In order to do anything with your objects at runtime you will probably want them in a list.
Without reading from a file or database, etc., the most concise way might be :
var Students = new List<Student>{
new Student { Name = "Bob", Age = 22, City = "Denver" },
new Student { Name = "Sally", Age = 33, City = "Boston" },
new Student { Name = "Alice", Age = 12, City = "Columbus" }
};
I don't know your end goal however, is this just mock data, like for a test?
Add constructor to Student like this
Student (string name, int age, string city)
{
Name = name;
Age = age;
City = city;
}
///
Student student1 = new Student("James", 19, "Los Angeles");
Well, if what you mean by more efficient way to do it is just to write less code, you could instanciate them assigning the property's values at once, just like:
Student student1 = new Student() { Name = "James", Age = 19, City = "Los Angeles" };
If you want not just to write less code, but to - let's say - read the data from another source (like a Json list, or a TXT file) you will have to write a loader for it.
Well, it depends what you are going to use it for. If it’s for testing, then you could use a custom built tool to create random Students:
public class RandomStudentCreator
{
private readonly Random rnd = new Random();
private readonly IList<string> cities, names;
private readonly int minAge, maxAge;
public RandomStudentCreator(
IList<string> names,
IList<string> cities,
int minimumInckusiveAge,
int maximumExclusiveAge)
{
//Argument validation here
this.cities = cities;
this.names = names;
minAge = minimumInckusiveAge;
maxAge = maximumExclusiveAge;
}
public Student Next()
{
var student = new Student();
student.Name = names[rnd.Next(names.Count);
student.City = cities[rnd.Next(cities.Count);
Student.Age = rnd.Next(minAge, maxAge);
}
}
If this is production code, then you should be creating students based on:
User input
Some data backend (DB, text file, etc.)
But in any case, you don’t want to create a variable for each student. You probably want a collection of students. Depending on what you want to do with them, the type of collection you need may vary, the framework gives you plenty of options:
Arrays: Student[]
Lists: List<Student>
Queues: Queue<Student>
Stacks: Stack<Student>
Sets: HashSet<Student>
Etc.
And last but not least, you probably want to implement a constructor in Student that takes a name, city and age to make instantiation a little bit more compact than what you currently have:
public class Student
{
public Student(string name,
int age,
string city)
{
Name = name;
Age = age;
City = city;
}
//...
}
var john = new Student(“John”, 19, “LA”);
Programming is not about typing data. Need a lot of data? - Load them from files, databases, servers, through GUI, etc.
You can make a handy constructor, you can make factories and builders, but they are not for creating hundreds of objects in a row. Even if it is historical data, one day you will want to change them, fix something in them. Believe me, it's much easier to separate them from the code and store somewhere else, than to edit hundreds of lines of code later.
If you want 500 students I suggest extracting data to a file, database etc. student1..student499 implementation looks very ugly: let's organize them into array: Student[] students. As an example, let's use the simplest csv file Students.csv solution in the format
name,age,city
E.g.
name,age,city
James,19,Los Angeles
Karen,20,San Diego
Bob,20,Dallas
Having the file completed you can easily read it:
using System.IO;
using System.Linq;
...
Student[] students = File
.ReadLines("Students.csv")
.Where(line => !string.IsNullOrWhiteSpace(line)) // Skip empty lines
.Skip(1) // Skip header
.Select(line => line.Split(','))
.Select(items => new Student() {
Name = items[0],
Age = int.Parse(items[1]),
City = items[2], })
.ToArray();
Sorry for the incoherent title. I don't know how to concisely explain my problem, which is why I didn't really know how to look it up. I'll explain using an example...
Let's say I have a class:
public class cas
{
public string name { get; set; }
public int num { get; set; }
}
With that class, I make several objects and stick them into a list. For the sake of example, I will make 4:
var list = new List<cas>
{
new cas { name = "firstname", num = 1 },
new cas { name = "firstname", num = 2 },
new cas { name = "lastname", num = 3 },
new cas { name = "lastname", num = 4 }
};
Is there a way to take this List and combine any objects with the same name field?
So, the new list would be 1 object with:
name = "firstname", num = 3,
name = "lastname", num = 7
There's the obvious "long" way to do it, but it would be clunky and expensive (go through the list several times to find like-objects). I was wondering if I was missing any clean way of doing it. I intentionally made a simple example so that the answer would be a proof of concept rather than writing my code for me. My actual problem is more complex than this, but I can't figure out this one aspect of it.
Using Linq, you have a GroupBy Method and a Select Method:
list = list.GroupBy(x=> x.name)
.Select(x=> new cas() { name = x.Key, num = x.Sum(y=> y.num) }).ToList();
Or using Elegant query-syntax:
list = (from item in list
group item by item.name into grouping
select new cas()
{
name = grouping.Key,
num = grouping.Sum(x => x.num)
}).ToList();
Note that to use these methods, you have to add using System.Linq at the top of your source file.
You can use linq, you would have to group them on name property and then sum on the num property of each group like:
var result = list.GroupBy(x=>x.name)
.Select(g=> new cas
{
name = g.Key,
num = g.Sum(x=>x.num)
});
I have a simple cache of objects:
Dictionary<int, Person> personCache = ...
personCache.Add(1, new Person(){ID = 1, Name = "John"});
personCache.Add(2, new Person(){ID = 2, Name = "Mary"});
personCache[1].Manager=personCache[2];
(In reality, I have proper encapsulation of the dictionary)
So now John's manager is set to Mary. However, if I want to replace Mary with a new instance of person, if I do
personCache[2] = new Person(){ID = 2, Name = "Kate"});
References to Mary are not replaced with references to Kate - i.e. John's manager is not updated.
I can see why this is - the dictionary has a reference to Kate, but John still holds a reference to Mary.
Can anyone suggest a way such that
personCache[2] = new Person(){ID = 2, Name = "Kate"});
Would have the 'expected' result and replace all references to Mary with a reference to Kate?
I think I need to obtain the reference stored in personCache[2] and change that reference to a new person.
Thank you
Ryan
Why not just search for the Manager directly and updated it where it points to the old value
Person oldPerson = personCache[2];
Person newPerson = new Person() { ID = 2, Name = "Kate" };
personCache[2] = newPerson;
foreach (var pair in personCache) {
if (pair.Value.Manager == oldPerson) {
pair.Vaulue.Manager = newPerson;
}
}
"... Would have the 'expected' result "
I believe it already has what most people would consider to the the expected result.
One way to achieve what you appear to want is to make the Name property of your Person class writable, then do:
personCache[2].Name = "Kate";
Another approach would be to store only the Id of the manager in your Person object, rather than a reference to the Manager. I.e. instead of:
personCache[1].Manager = personCache[2];
You could have:
personCache[1].ManagerId = 2;
And you could, for example, have an extension method to get the Manager for a Person:
public static Person GetManager(this Person person)
{
if (person == null) throw new ArgumentNullException("person");
Person manager;
personCache.TryGetValue(person.ManagerId, out manager);
return manager; // returns null if not found in cache
}
Say Suppose you have a class
public class Person
{
public int PesronId{get;set;}
public string FirstName{get;set;}
public string LastName{get;set;}
public string Gender{get;set;}
}
Now We create an object p1
Person p1 = new Person();
Next we have values from textboxes to be assigned to p1
eg.
p1.PersonId = textbox1.text;
p1.FirstName = textbox2.text;
p1.LastName = textbox3.text;
Is there a more efficient way of doing this in Visual Studio 2010, by which I will get something like this
p1.PersonId =
p1.FirstName =
p1.LastName =
so that I dont have to manually type the properties for p1.
Or is then an alternate syntax that I can use.
There's simpler syntax for the code:
Person p1 = new Person
{
PersonId = textbox1.Text,
FirstName = textbox2.Text,
LastName = textbox3.Text
};
This is object initializer syntax, introduced in C# 3.
I think I'd misread the question though - it sounds like you're just interested in cutting down the typing required. There may be something which will do that, but personally I find IntelliSense is fine on its own. The readability of the code afterwards is much more important than the time spent typing, IMO.
You might also want to add a constructor to Person to take all the relevant property values - that would simplify things too, and with C# 4's named argument support, you can retain readability.
You can use the new initialization functionality in C#:
Person p1 = new Person()
{
PersonId = textbox1.text,
FirstName = textbox2.text,
LastName = textbox3.text
};