public class Unit
{
public int UnitId { get; set; }
public Engine EngineStuff { get; set; }
}
public class Engine
{
public int PS { get; set; }
public int MaxSpeed { get; set; }
}
var unit = new Unit();
unit.UnitId = 3; //OK because Unit-constructor was called
unit.EngineStuff.PS = 200; //error, because EngineStuff-constructor obviously wasn't called.
How can this "inner" constructor be called?
I thought it initializes it automatically?
How can I simply assign a value to the property "EngineStuff.PS"?
You have to instantiate object's properties explicitly:
public class Unit
{
public Unit()
{
EngineStuff = new Engine();
}
}
Or if you want to manually control when to instantiate:
var unit = new Unit();
unit.UnitId = 3;
unit.EngineStuff = new Engine();
unit.EngineStuff.PS = 200;
or simpler:
var unit = new Unit { UnitId = 3 };
unit.EngineStuff = new Engine { PS = 200 };
Simply you need to initialize EngineStuff in either Unit constructor or just before using it.
public class Unit
{
public Unit()
{
EngineStuff = new Engine();
}
public int UnitId { get; set; }
public Engine EngineStuff { get; set; }
}
Or :
var unit = new Unit();
unit.UnitId = 3;
unit.EngineStuff = new Engine():
unit.EngineStuff.PS = 200;
EngineStuff is just a reference, you need to set its value to an Engine object that you create, either in the Unit constructor, a property initializer, or plain code.
So either:
// Constructor
public class Unit
{
public Unit() { EngineStuff = new Engine(); }
public int UnitId { get; set; }
public Engine EngineStuff { get; set; }
}
Or
// Property initializer
var unit = new Unit
{
UnitId = 3,
EngineStuff = new Engine { PS = 200 }
};
Or
// Plain code
var unit = new Unit();
unit.UnitId = 3;
unit.EngineStuff = new Engine { PS = 200 };
No, you need to set it explicitly like below cause EngineStuff is of type Engine and so you will have instantiate it first before accessing any of it's member.
unit.EngineStuff = new Engine { PS = 10, MaxSpeed = 2000 };
(OR) you can change your Unit class to have EngineStuff as a getter property and have the instance created there like below
public Engine EngineStuff
{
get
{
return new Engine();
}
}
Then you can access it
var unit = new Unit();
unit.UnitId = 3;
unit.EngineStuff.PS = 100;
Addition to other answers, you can define a getter property to create the instance when you need it first time:
public class Unit
{
public int UnitId { get; set; }
private Engine engineStuff;
public Engine EngineStuff
{
get
{
if (engineStuff == null) engineStuff = new EngineStuff();
return engineStuff;
}
}
}
Related
I have to an upper class with nested classes
public class Preferences
{
public FunctionClass function { get; set; } = new FunctionClass();
public class FunctionClass
{
public string programfolder { get; set; } = "";
...
}
public LoggerClass logger { get; set; } = new LoggerClass();
public class LoggerClass
{
public string logFolder { get; set; } = "Log";
...
}
public OptionClass options { get; set; } = new OptionClass();
public class OptionClass
{
public bool showGraphics { get; set; } = true;
...
}
public MqttSpSetupClass MqttSpSetup { get; set; } = new MqttSpSetupClass();
public class MqttSpSetupClass
{
public string strAddress { get; set; } = "localhost";
...
}
}
so I want reflection to cycle on all member of each inner class
PropertyInfo[] props_Outer = typeof(IoAppPreferences).GetProperties();
int counter = 0;
foreach (PropertyInfo prop_Upper in props_Outer)
{
var sName_Outer = prop_Upper.Name;
var val_Outer = props_Outer.GetValue(counter ++);
PropertyInfo[] properties_Inner;
switch (sName_Outer.ToUpper())
{
case "DIMS": properties_Inner = typeof(IoAppPreferences.DimsClass).GetProperties(); break;
...
}
foreach (PropertyInfo prop_Inner in properties_Inner)
{
var sName = prop_Inner.Name;
//prefs.function
var sVal = prop_Inner.GetValue(val_Outer);<------ERROR
switch (prop_Inner.Name.ToUpper())
{
...
}
}
I get an error where I put the arrow. And the reason is that val_Outer is FunctionClass function while if I hardcode prefs.function it is ok. Of course, I can put a switch per each one, but my question is: is there a better way to solve it?
I have seen this solution but can't fit to my needs
You got error because val_Outer is wrong instance. You are trying to get value out of counter integer props_Outer.GetValue(counter ++)
If your goal is to get property values from nested classes you must have instance of Preferences object:
var appPreferences = new Preferences();
var propsOuter = appPreferences.GetType().GetProperties();
foreach (var po in propsOuter)
{
var valueOuter = po.GetValue(appPreferences);
Console.WriteLine($"{po.Name}");
if (valueOuter == null) continue;
var propsInner = valueOuter.GetType().GetProperties();
foreach (var pi in propsInner)
{
var valueInner = pi.GetValue(valueOuter);
Console.WriteLine($"{pi.Name}: {valueInner}");
}
}
But getting values through reflection is pretty much useless if you already have object instance.
I'm using C# and have created an object to send to a JSON service that looks like this:
public class SendRequest
{
public string id { get; set; }
public string case { get; set; }
public string method { get; set; }
public Volume value { get; set; }
}
public class Volume
{
public int level;
public bool mute;
}
I can code hint when setting the sub object:
var _req = new SendRequest();
_req.value.mute = false;
_req.value.level = 50;
But when the program is run, the sub-object itself is null (_req.value = null) and the two items under that object don't show.
Why is this happening?
You need to initialize the "value" to something.
Add this constructor to your SendRequest class:
public SendRequest(){ value = new Volume(); }
You can use object initializers
var _req = new SendRequest()
{
value = new Volume()
{
mute = false,
level = 50,
},
};
at this point method is null
public string method { get; set; }
longer but what you can do is
private string method = string.empty;
public string Method { get {return method;} set {method = value;} }
value is just a bad name
private Volume volume = new Volume();
public Volume Volume { get {return volume;} set {volume = value;} }
or
volume = new Volume (mute = false, value.level = 50);
Can someone suggest an alternative way to solve this problem, I don't want to use SWITCH statement in my code.
Class Definition:
public class Rootobject
{
public Must[] must { get; set; }
public Should[] should { get; set; }
}
public class Should
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Must
{
public Match match { get; set; }
public Bool _bool { get; set; }
}
public class Match
{
public string pname { get; set; }
}
public class Bool
{
public string rname { get; set; }
}
Function Definition
public root getobject(string op)
{
Rootobject root = new Rootobject();
op ="must";
switch (op)
{
case "should":
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
break;
case "must":
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
break;
}
return(root);
}
Switch statement is an overhead an new type comes then i may need to add another condition. Can anyone suggest an alternative way of using switch statement.
Based on the comments under your question, I discovered it is possible to implement what #Jon Skeet stated.
You can add an Initialize Method in your RootObject class to create the dictionary (Use a ref Dictionary so to avoid setting the dictionary in your RootObject class that could change the structure of your serialization):
public void Initialize(ref Dictionary<string, Func<Rootobject>> rootDic)
{
Func<Rootobject> shouldFunc = () =>
{
Rootobject root = new Rootobject();
root.should = new Should[1];
Should objShould = new Should();
objShould.match = new Match();
objShould.match.pname = "hello";
root.should[0] = objShould;
return root;
};
Func<Rootobject> mustFunc = () =>
{
Rootobject root = new Rootobject();
root.must = new Must[1];
Must objMust = new Must();
objMust.match = new Match();
objMust.match.pname = "hello";
root.must[0] = objMust;
return root;
};
rootDic.Add("should", shouldFunc);
rootDic.Add("must", mustFunc);
}
And then call it in your getobject method like so:
public static Rootobject getobject(string op)
{
Dictionary<string, Func<Rootobject>> rootDic = new Dictionary<string,Func<Rootobject>>();
Rootobject root = new Rootobject();
root.Initialize(ref rootDic);
if(rootDic.Count > 0)
return rootDic[op].Invoke();
return new Rootobject();
}
You still going to get the same result as the solution in your question even after serializing it.
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");
I'm new to programming and this may be a simple issue but I can't seem to figure it out. I have the following 2 classes in my program:
public class TrackingObject
{
public int OrderId { get; set; }
public int ProjectCount { get; set; }
public IList<ProjectInfo> Projects { get; set; }
}
public class ProjectInfo
{
public int ProjectId { get; set; }
public string ProjectType { get; set; }
public int ImageCount { get; set; }
}
For testing I created a console application and used the following code:
static void Main(string[] args)
{
TrackingObject oTracking = new TrackingObject();
ProjectInfo pInfo = new ProjectInfo();
oTracking.OrderId = 1;
oTracking.ProjectCount = 1;
pInfo.ProjectId = 1;
pInfo.ProjectType = "CANVAS";
pInfo.ImageCount = 1;
oTracking.Projects.Add(pInfo);
Console.WriteLine(oTracking.Projects.Count);
Console.ReadLine();
}
When I run the application it throws a NullReferenceException was unhandled on the following line:
oTracking.Projects.Add(pInfo);
I understand enough to know that the exception is because oTracking.Projects is NULL. What is the correct way to accomplish what I am attempting? Any guidance will be most appreciated.
Add oTracking.Projects = new List<ProjectInfo>() before adding items to it.
Combination of I4V's answer and first comment on that answer:
public class TrackingObject
{
public int OrderId { get; set; }
public int ProjectCount { get; set; }
public IList<ProjectInfo> Projects { get; set; }
public TrackingObject() {
this.Projects = new List<ProjectInfo>();
}
//This constructor optional, but since you're using an IList, may as well
//let the user pass in an IList of a different type if they chose
public TrackingObject(IList<ProjectInfo> defaultList) {
this.Projects = defaultList;
}
}
Check if the object if null, if it is assign a new instance:
if (oTracking.Projects == null) {
oTracking.Projects = new List<ProjectInfo>();
}
Projects needs to be initialized:
oTracking.Projects = new List<ProjectInfo>();
static void Main(string[] args)
{
TrackingObject oTracking = new TrackingObject();
ProjectInfo pInfo = new ProjectInfo();
oTracking.OrderId = 1;
oTracking.ProjectCount = 1;
pInfo.ProjectId = 1;
pInfo.ProjectType = "CANVAS";
pInfo.ImageCount = 1;
oTracking.Projects = new List<ProjectInfo>();
oTracking.Projects.Add(pInfo);
Console.WriteLine(oTracking.Projects.Count);
Console.ReadLine();
}