I have a class
public class MyCoolProp
{
public string FullName {get;set;}
}
and in another Class i have this as Property:
public class MyMainClass
{
public MyCoolProp coolprop {get;set;}
public void DoSomething()
{
MessageBox.Show(nameof(coolprop.FullName));
}
}
The Actual Result is: "Fullname"
But i want a combination like this: "coolprop.FullName"
i dont want to do something like this:
nameof(coolprop) + "." + nameof(coolprop.FullName);
Maybe its possible in an extension?
If i rename the Property "coolprop" the output should also have the new name
Depending on exactly what you want to do, you might be able to use CallerArgumentExpressionAttribute. That does mean you need to be willing to actually evaluate the property as well, even if you don't use it.
Note that this requires a C# 10 compiler.
Here's a complete example:
using System.Runtime.CompilerServices;
public class MyCoolProp
{
public string FullName { get; set; }
}
class Program
{
static MyCoolProp CoolProp { get; set; }
static void Main()
{
CoolProp = new MyCoolProp { FullName = "Test" };
WriteTextAndExpression(CoolProp.FullName);
}
static void WriteTextAndExpression(string text,
[CallerArgumentExpression("text")] string expression = null)
{
Console.WriteLine($"{expression} = {text}");
}
}
Output: CoolProp.FullName = Test
Source:
get name of a variable or parameter (modified a bit adjusted with your case)
You can use what System.Linq.Expression provides
code example:
using System.Linq.Expression
class Program
{
public static MyCoolProp coolProp { get; set; }
static void Main(string[] args)
{
coolProp = new MyCoolProp() { FullName = "John" };
DoSomething();
}
public static string GetMemberName<T>(Expression<Func<T>> memberExpression)
{
MemberExpression expressionBody = (MemberExpression)memberExpression.Body;
return expressionBody.ToString();
}
public static void DoSomething()
{
string prop = GetMemberName(() => coolProp.FullName);
Console.WriteLine(prop);
}
}
public class MyCoolProp
{
public string FullName { get; set; }
}
the GetMemberName method will return the namespace, class name, object name, and variable name (depends where the method is being called)
Output: Program.coolProp.FullName
Let's say I have a class StockMarket which has a list of Companies.
class StockMarket : IStock
{
private static List<IObserverPush> observersPush;
private static List<IObserverPull> observersPull;
public static List<Company> Companies { get; private set; }
public StockMarket()
{
observersPush = new List<IObserverPush>();
observersPull = new List<IObserverPull>();
Companies = new List<Company>() { new Company("Unilever", "UNA", 47.72, 0.77, 1.63, -3.45, "135B"),
new Company("ING Groep", "INGA", 13.40, -0.07, -0.50, -12.38, "60.4B"),
new Company("ArcelorMittal", "MT", 29.50, 0.14, 0.48, 36.05, "54.6B"),
new Company("ASML Holding", "ASML", 167.40, 2.00, 1.21, 36.49, "53.3B"),
new Company("Heineken", "HEIA", 87.66, -0.02, -0.02, 2.80, "49B"),
new Company("RELX", "REN", 18.15, 0.17, 0.95, -0.22, "38.9B"),
new Company("Philips", "PHIA", 35.49, 0.17, 0.47, 7.61, "33.3B"),
new Company("Unibail Rodamco", "UL", 196.40, -0.15, -0.08, -16.78, "20.3B"),
new Company("Akzo Nobel", "AKZA", 75.68, -0.16, -0.21, 0.33, "19.4B"),
new Company("Altice", "ATC", 7.58, 0.16, 2.16, -66.30, "17.6B")};
Thread thread = new Thread(SimulateMarket);
thread.Start();
}
public void Subscribe(IObserverPull o)
{
observersPull.Add(o);
o.UpdateMarket();
}
public void Unsubscribe(IObserverPull o)
{
observersPull.Remove(o);
}
public void Subscribe(IObserverPush o)
{
observersPush.Add(o);
o.UpdateMarket(Companies);
}
public void Unsubscribe(IObserverPush o)
{
observersPush.Remove(o);
}
public void NotifyObservers()
{
foreach(IObserverPush o in observersPush)
{
o.UpdateMarket(Companies);
}
foreach(IObserverPull o in observersPull)
{
o.UpdateMarket();
}
}
public void SimulateMarket()
{
while(observersPush.Count + observersPull.Count > 0)
{
//randomly change property values of companies
//and notify the observers about the changes
}
}
}
Company class has some properties.
public class Company
{
public string Name { get; private set; }
public string Symbol { get; private set; }
public double Price { get; set; }
public double Change { get; set; }
public double ChangePercentageDay { get; set; }
public double ChangePercentageYear { get; set; }
public string Capital { get; private set; }
public Company(string name, string symbol, double price, double change, double changePercentageDay,
double changePercentageYear, string capital)
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
ChangePercentageDay = changePercentageDay;
ChangePercentageYear = changePercentageYear;
Capital = capital;
}
}
The Forms have references to the StockMarket and they use it to retrieve data about the companies and to display it.
Form 1
public partial class ConcreteObserverPush : Form, IObserverPush
{
private StockMarket stockMarket;
public ConcreteObserverPush()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket(List<Company> companies)
{
stockMarketListView.Items.Clear();
foreach(Company c in companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPush_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
Form 2
public partial class ConcreteObserverPull : Form, IObserverPull
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
stockMarket.Subscribe(this);
}
public void UpdateMarket()
{
stockMarketListView.Items.Clear();
foreach (Company c in StockMarket.Companies)
{
ListViewItem item = new ListViewItem(c.Symbol);
item.SubItems.Add(c.Name);
item.SubItems.Add(c.Price.ToString());
item.SubItems.Add(c.Change.ToString());
item.SubItems.Add(c.ChangePercentageDay.ToString() + "%");
item.SubItems.Add(c.ChangePercentageYear.ToString() + "%");
item.SubItems.Add(c.Capital);
stockMarketListView.Items.Add(item);
}
}
private void ConcreteObserverPull_FormClosing(object sender, FormClosingEventArgs e)
{
stockMarket.Unsubscribe(this);
}
}
The problem is that if the Form gets the list of companies through the property on StockMarket it can change their state. However, I want only StockMarket to have the ability to change the state of the company.
So what would be the best way to share Company state with Form when requested and preventing the Form from modifying it.
I know that a possible solution would be to return clones of Company objects, but I believe there should be a better solution.
Any help is appreciated!
The general gist of this would be to make your Company object immutable. Then you would add methods to the StockMarket object to manipulate the Company list and replace entries with new ones when you want to change a value.
Here's a quick example put together in LINQPad of making the Company class immutable and adding an UpdatePrice method to the StockMarket class.
Whether you want to be able to manipulate the Companies property from outside the StockMarket can be handled by returning the list as ReadOnlyCollection so that it's size can't be manipulated by a consumer.
void Main()
{
var sm = new StockMarket();
sm.Companies.Add(new Company("Test", "TST", 50, 0));
sm.UpdatePrice("Test", 45);
var testCompany = sm.Companies.First(x => x.Name == "Test");
Console.WriteLine($"{testCompany.Name},{testCompany.Symbol},{testCompany.Price},{testCompany.Change}");
//Output: Test,TST,45,-5
}
class StockMarket
{
public List<Company> Companies { get; private set; } = new List<Company>();
public void UpdatePrice(string name, double price) {
var index = Companies.FindIndex(x => x.Name == name);
if(index >= 0)
{
var previous = Companies[index];
Companies[index] = new Company(previous.Name, previous.Symbol, price, price - previous.Price);
}
}
}
class Company
{
public Company(string name, string symbol, double price, double change) {
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
public string Name { get; }
public string Symbol { get; }
public double Price { get; }
public double Change { get; }
///...
}
This would be a solution:
Create the Company class as a Private Inner Class inside of the StockMarket class, that way it'd only be accessible inside of it, and then provide an interface that only includes the get of all the properties and make Company implement it. You would have to make StockMarket's Company list to be the Interface's type.
Any modification you'd have to do you'd do it by casting the interface's List objects into the original class type.
Example:
class Program
{
public static StockMarket stockMarket = new StockMarket();
static void Main(string[] args)
{
}
}
public interface ICompany
{
string Name { get; }
}
public class StockMarket
{
public StockMarket()
{
Companies = SomeWildFunctionThatRetrievesAllCompanies();
}
public void OneWildFunctionThatModifiesACompany()
{
Company dunno = (Company)Companies[0];
dunno.Name = "Modification Made Possible";
}
private List<ICompany> SomeWildFunctionThatRetrievesAllCompanies()
{
return new List<ICompany>(new List<Company>());
}
public List<ICompany> Companies { get; private set; }
private class Company : ICompany
{
public string Name { get; set; }
}
}
Try this:
class Company
{
public Company(Type type,string name,string symbol,double price, double change)
{
if (type.Name == "StockMarket")
{
Name = name;
Symbol = symbol;
Price = price;
Change = change;
}
}
private string Name { get; set; }
private string Symbol { get; set; }
private double Price { get; set; }
private double Change { get; set; }
///...
}
This will allow you to change the state only if the type is StockMarket
like:
class StockMarket
{
public List<Company> Companies { get; set; }
public StockMarket()
{
Companies = new List<Company>();
}
public StockMarket someMethod()
{
//You can change the state here
StockMarket s = new StockMarket();
s.Companies.Add(new Company(this.GetType(), "aa", "_", 123, 1234));
return s;
}
//...
}
Now you cannot change the state here:
public partial class Observer: Form
{
private StockMarket stockMarket;
public ConcreteObserverPull()
{
InitializeComponent();
stockMarket = new StockMarket();
//Here you cannot change the state
stockMarket.Companies.Add(new Company(this.GetType(), "aa", "_", 123,12));
}
//...
}
Sorry, I don't know C#, but as an idea, you can wrap returned entities with decorator or proxy, which will throw an exception in case of trying to modify state of a company.
Returning clones with fields set as readonly is the safest way to go.
Hey guys I want to achieve something like this
class Program
{
static void Main(string[] args)
{
Responsible responsible = new Responsible()
{
//I want here to populate with PopulatePerson the base members
Phone = "93827382",
Company = "Google"
};
}
public Person PopulatePerson(string pName, string pLastName)
{
Person person = new Person();
person.Name = pName;
person.LastName = pLastName;
return person;
}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
}
public class Responsible : Person
{
public string Phone { get; set; }
public string Company { get; set; }
}
The case is more complex with database queries and stuff but basically this is what I need
I could use a member called Person in Responsible and do Person = PopulatePerson("Dan", "Johns") but since I'm inheriting I find it kinda redundant
What about something like this. I created a generic (static) factory method for Person that is reusable across all types that inherit from Person.
class Program
{
static void Main(string[] args)
{
//Responsible responsible = new Responsible()
//{
// //I want here to populate with PopulatePerson the base members
// Phone = "93827382",
// Company = "Google"
//};
var responsible = Responsible.Populate("Glenn", "Fake", "93827382", "Google");
//responsible
}
// NO LONGER NEEDED
// ============================
//public Person PopulatePerson(string pName, string pLastName)
//{
// Person person = new Person();
// person.Name = pName;
// person.LastName = pLastName;
// return person;
//}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
public static TPerson Populate<TPerson>(string name, string lastname) where TPerson : Person, new()
{
TPerson person = new TPerson();
person.Name = name;
person.LastName = lastname;
return person;
}
}
public class Responsible : Person
{
public static Responsible Populate(string name, string lastname, string phone, string company)
{
var p = Responsible.Populate<Responsible>(name, lastname);
p.Phone = phone;
p.Company = company;
return p;
}
public string Phone { get; set; }
public string Company { get; set; }
}
Not sure if it makes sense your real scenario but you could change PopulatePerson to accept a Person object as an input parameter instead of internally creating a new one. Then you could pass your new Responsible object to it and afterwards set Phone and Company.
Edit: Like this
class Program
{
static void Main(string[] args)
{
Responsible responsible = new Responsible();
PopulatePerson(responsible, "first", "last");
responsible.Phone = "93827382";
responsible.Company = "Google";
}
public static void PopulatePerson(Person person, string pName, string pLastName)
{
person.Name = pName;
person.LastName = pLastName;
}
}
public class Person
{
public string Name { get; set; }
public string LastName { get; set; }
}
public class Responsible : Person
{
public string Phone { get; set; }
public string Company { get; set; }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment5
{
public class Person
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
public class Student : Person
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public static int countS = 0;
public static List<string> studentlist = new List<string>();
public Student()
{
studentlist.Add(Name);
countS++;
}
public static int GetActiveInstances()
{
return countS;
}
}
class MainProgram
{
static void Main(string[] args)
{
// Instantiate three Student objects.
Student Student1 = new Student();
Student Student2 = new Student();
Student Student3 = new Student();
Student1.Name = "John";
Student2.Name = "Joe";
Student3.Name = "Jacob";
for (int i = 0; i < Student.studentlist.Count; i++) // Loop with for.
{
Console.WriteLine(Student.studentlist[i]);
}
Console.WriteLine("Press any key to continue . . . ");
Console.ReadKey();
}
}
}
Hi guys. What I have in mind is that I want to automatically store every student being initiated in an array/list that I created and eventually, I want to output these students in the console.
Can anyone enlighten me what I did wrong on my program?
Supposedly it will output the 3 names I declare. What I have on the output for the posted program are all blank.
**Next Related Question **
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Assignment6
{
public class Person
{
public string Name { get; set; }
public string Address { get; set; }
public virtual void GetInfo()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("Address: {0}", Address);
}
}
public class Student : Person
{
public void SetStudentInfo(string name, string address)
{
Name = name;
Address = address;
}
}
public class Course //class represents university course
{
private ArrayList studentList = new ArrayList();
public ArrayList StudentList
{
get { return studentList; }
set { studentList = value; }
}
//how can I implement this such that I can have the StudentList be updated and printed
// out to the console from the main
public void ListStudents()
{
foreach (Student i in StudentList)
{
Console.WriteLine(i.ToString());
}
}
}
class MainProgram
{
static void Main(string[] args)
{
var Student1 = new Student { Name = "John" };
var Student2 = new Student { Name = "Joe" };
var Student3 = new Student { Name = "Jacob" };
Course course1 = new Course();
course1.StudentList.Add(Student1);
course1.StudentList.Add(Student2);
course1.StudentList.Add(Student3);
course1.ListStudents();
Console.WriteLine();
Console.WriteLine("Press any key to continue . . . ");
Console.ReadKey();
}
}
}
I have this code and I want to output every student in my arraylist, the foreach loop should be on the course class. Still, the code is connected on my question so I just ask it here. Can anyone help me revise it? thanks
What I do not get is these line:
public static int countS = 0;
public static List<string> studentlist = new List<string>();
public Student()
{
studentlist.Add(Address);
countS++;
}
What I would suggest is to move these out so that the class is something like this:
public class Person
{
public string Name { get; set; }
public DateTime BirthDate { get; set; }
}
public class Student : Person
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
}
And that main is something like this:
static void Main(string[] args)
{
// Instantiate three Student objects.
Student Student1 = new Student();
Student Student2 = new Student();
Student Student3 = new Student();
Student1.Name = "John";
Student2.Name = "Joe";
Student3.Name = "Jacob";
var studentlist = new List<Student>{Student1,Student2,Student3};
foreach (var student in studentlist)
{
Console.WriteLine(student.Name);
}
Console.WriteLine("Press any key to continue . . . ");
Console.ReadKey();
}
Instead of adding a property that hasn't been set yet (which is what you're currently doing in the default constructor - you're adding the Name property before it's been set), you can add a reference to the class instance using the this keyword, so the properties of the items in your list (like Name or Address) get updated when they are set on the class instance.
Also, you don't need a separate variable to keep track of the number of students, since you can just use the Count property of the list.
Here's a way you can do this:
public class Student : Person
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
public static List<Student> AllStudents = new List<Student>();
public Student()
{
AllStudents.Add(this);
}
public static int GetActiveInstances()
{
return AllStudents.Count;
}
}
Usage:
public static void Main()
{
var student1 = new Student {Name = "John"};
var student2 = new Student {Name = "Joe"};
var student3 = new Student {Name = "Jacob"};
foreach (var student in Student.AllStudents)
{
Console.WriteLine(student.Name);
}
}
Output:
JohnJoeJacob
UPDATE
One way you can protect your internal list, yet still let others query it, would be to make the list private, and then expose a public property that returns a copy of the list, which prevents people from affecting your private instance if they call .Add() or .Remove() on it, or try to set it to a new List<Student>.
Here's an example:
public class Student : Person
{
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostalCode { get; set; }
public string Country { get; set; }
// This is the "official" list. It's private so cannot be changed externally
private static readonly List<Student> StudentList = new List<Student>();
// This property returns a COPY of our private list
public static List<Student> AllStudents
{
get
{
var copyOfList = new List<Student>();
copyOfList.AddRange(StudentList);
return copyOfList;
}
}
public Student()
{
// Add the student to our private list
StudentList.Add(this);
}
public static int StudentCount()
{
// Return the count from our private list
return StudentList.Count;
}
}
I have a class with properties:
public class TaskConfiguration
{
public string Task_Name
{
get; set;
}
public string task_id
{
get; set;
}
}
And somewhere in the code I have a method to set the properties of the class early on upon program execution:
public class TaskManagingProcess
{
public void InsertTaskProperties()
{
TaskConfiguration tc = new TaskConfiguration();
tc.Task_Name = "Sample Task";
tc.task_id = "1";
}
}
Later in execution, in another class, I want to modify the properties of the TaskConfiguration class, but I'm not sure how. If I use the following, it will not work because it creates a new instance of the TaskConfiguration class.
TaskManagingProcess tmp = new TaskManagingProcess;
tmp.InsertTaskProperties();
So how can I do this?
You want to pass the object:
public void InsertTaskProperties(TaskConfiguration config) {
config.Task_Name = "Sample Task";
config.task_id = "1";
}
Then:
TaskManagingProcess tmp = new TaskManagingProcess();
TaskConfiguration config = new TaskConfiguration();
tmp.InsertTaskProperties(config);
(I am making an awfully large assumption about your code.. but this should give you the basic idea)
It looks to me like TaskManagingProcess is a proxy class that's why I would recommend something like:
public class TaskConfiguration
{
public string Task_Name
{
get;
set;
}
public string task_id
{
get;
set;
}
}
public class TaskManagingProcess
{
private TaskConfiguration taskConfiguration;
public TaskManagingProcess(TaskConfiguration taskConfiguration)
{
this.taskConfiguration = taskConfiguration;
}
public void InsertTaskProperties(string taskId, string name)
{
taskConfiguration.task_id = taskId;
taskConfiguration.Task_Name = name;
}
}
So at the end you could do this (see below) and easily add code to handle the access at your TaskConfiguration object:
TaskConfiguration taskConfiguration = new TaskConfiguration() { task_id = "1", Task_Name = "Sample Task" };
TaskManagingProcess taskManaginProcess = new TaskManagingProcess(taskConfiguration);
taskManaginProcess.InsertTaskProperties("2", "Sample Task 2");