I have the following code
class TopClass
{
public string ClsProp1 { get; set; }
public string ClsProp2 { get; set; }
public SubClass ClsProp3 { get; set; }
}
class SubClass
{
public string SCProp1 { get; set; }
public string SCProp2 { get; set; }
}
class Program
{
static void Main(string[] args)
{
Test.TopClass TCN = new Test.TopClass();
TCN.ClsProp1 = "TCProp1--string value";
TCN.ClsProp2 = "TCProp2--string value";
TCN.ClsProp3.SCProp1 = "SCProp1--string value";
TCN.ClsProp3.SCProp2 = "SCProp2--string value";
}
}
I can't seem to figure out how to instantiate the TCN.ClsProp3.ScProp1 and TCN.ClsProp3.ScProp2 values. I keep getting the "An unhandled exception of type 'System.NullReferenceException' occurred in Test.exe
Additional information: Object reference not set to an instance of an object." error message. Forgive my ignorance, I'm really trying to learn OOP from scratch.
Thanks in advance
You need to initialize the ClsProp3 object before you can use it.
TCN.ClsProp3 = new SubClass();
You could also initialize it in the TopClass constructor like this:
class TopClass
{
public TopClass()
{
ClsProp3 = new SubClass();
}
public string ClsProp1 { get; set; }
public string ClsProp2 { get; set; }
public SubClass ClsProp3 { get; set; }
}
When learning, it's better to pick a good domain. TopClass with ClsPropX do not make for a nice learning experience.
As for your original question, launch the debugger and see what the ClsProp3 equals to. And bear in mind that it's impossible to assign anything to "nothingness", which is null in C# parlance.
Related
I have different classes sharing some properties of same type and name. I wish to assign same property values to each other. I explain my intention better in comments in the following pseudo-code. Is it possible in C#?
Ponder that there are a plethora of common properties but in unrelated classes, must we assign them one-by-one?
Second case is about sharing same properties but some of them may be nullable, who knows!
Side note: the classes already exist, cannot be altered, touched. Kinda sealed.
Can't it be done using nameofoperator and two for loops? Compare property names if matched, assign?
using System;
namespace MainProgram
{
class HomeFood
{
public DateTime Date { get; set; }
public string food1 { get; set; }
public string food2 { get; set; }
public int cucumberSize { get; set; }
}
class AuntFood
{
public string food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime Date { get; set; }
public string food1 { get; set; }
// extra
public double? length { get; set; }
}
class GrandpaFood
{
public string? food2 { get; set; }
public int cucumberSize { get; set; }
public DateTime? Date { get; set; }
public string food1 { get; set; }
// extra
}
static class Program
{
public static void Main(string[] args)
{
var home = new HomeFood
{
Date = new DateTime(2020, 1, 1),
food1 = "cucumber",
food2 = "tomato",
cucumberSize = 123
};
var aunt = new AuntFood();
/*
First case: same types
Expected for-each loop
assigning a class's property values
to other class's property values
or for-loop no matter
foreach(var property in HomeFood's properties)
assign property's value to AuntFood's same property
*/
var home2 = new HomeFood();
var grandpa = new GrandpaFood
{
Date = new DateTime(2020, 1, 1),
food1 = "dfgf",
food2 = "dfgdgfdg",
cucumberSize = 43534
};
/*
Second case: similar to first case
with the exception of same type but nullable
or for-loop no matter
foreach(var property in GrandpaFood's properties)
assign property's value to GrandpaFood's same property
we don't care if it is null e.g.
Home2's same property = property's value ?? default;
*/
}
}
}
Based on the comments in the questions, this is just to show how it can be done with reflection.
Disclaimer, this is just a very simplified example on how to use reflection to sync properties. It does not handle any special cases (modifiers, read only, type mismatch, etc)
I would strongly suggest to use automapper to achieve the qp goals.
public class Type1
{
public string Property1 { get; set; }
public string Property2 { get; set; }
}
public class Type2
{
public string Property1 { get; set; }
public string Property3 { get; set; }
}
class Program
{
static void Main(string[] args)
{
var t1 = new Type1 { Property1 = "Banana" };
var t2 = new Type2();
var properties1 = typeof(Type1).GetProperties().ToList();
var properties2 = typeof(Type2).GetProperties().ToList();
foreach(var p in properties1)
{
var found = properties2.FirstOrDefault(i => i.Name == p.Name);
if(found != null)
{
found.SetValue(t2, p.GetValue(t1));
}
}
Console.WriteLine(t2.Property1);
}
}
The short answer is, apply OOP. Define a base Food class and inherit from it in any specific food classes you have. You can put all the shared props in the base class.
public class Food
{
public string food2 { get; set; }
// other shared stuff
}
class GrandpaFood : Food
{
// other specific stuff
}
As others have said, use some of the Object Oriented properties, like inheriting a super class of implement an interface.
In case you go for inheritance, consider making the super class (the one you inherit from) abstract. This means that the super class itself cannot be instantiated, which greatly reduces the risk of violating the Liskov Substitutional Principle. Also it often reflects the real problem better. In your example, this would also be the case, as “food” is not an actual thing in the real world, but rather a group of things.
I always get a "An unhandled exception of type 'System.NullReferenceException' occurred in myapp.exe" when code reaches _match.Players2.Add(_hero);
I am not sure why, I initialized _match as well as _hero, when I debug I see that there are no null values. I am not sure why I am getting this exception, am I missing something?
Here is my code:
public static List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)
{
var HeroCollection = new List<MyDotaClass.DotaHero>();
var MatchCollection = new List<MyDotaClass.MatchHistory>();
string response = GetDotaWebResponse(uri);
dotadata.Dota.MatchHistoryRootObject matches = JsonConvert.DeserializeObject<dotadata.Dota.MatchHistoryRootObject>(response);
foreach (var match in matches.result.matches)
{
var _match = new MyDotaClass.MatchHistory();
_match.MatchID = match.match_id.ToString();
foreach (var player in match.players)
{
var _hero = new MyDotaClass.DotaHero();
foreach(var h in heros)
{
if(player.hero_id.ToString().Equals(h.HeroID))
{
_hero.HeroName = h.HeroName;
_hero.HeroNonCleanName = h.HeroNonCleanName;
_hero.HeroID = h.HeroID;
_match.Players2.Add(_hero);
}
}
}
MatchCollection.Add(_match);
}
return MatchCollection;
}
public class MyDotaClass
{
public class DotaHero
{
public string HeroName { get; set; }
public string HeroNonCleanName { get; set; }
public string HeroID { get; set; }
}
public class MatchHistory
{
public string MatchID { get; set; }
//public List<DotaHero> Players { get; set; }
public List<MyDotaClass.DotaHero> Players2 { get; set; }
}
UPDATE:
For those interested in Dota, I lost all of my original code so I am rewriting and doing my best to make a tutorial out of it. http://uglyvpn.com/2014/07/21/dota-2-net-c-tool-pt1/
Make sure the list in Players2 is initialized properly. It could be done in your foreach loop, like this:
foreach (var match in matches.result.matches)
{
var _match = new MyDotaClass.MatchHistory();
_match.MatchID = match.match_id.ToString();
_match.Players2 = new List<MyDotaClass.DotaHero>();
...
But that's not a great design. It would be more robust to initialize it in the MatchHistory constructor, like this:
public class MatchHistory
{
public string MatchID { get; set; }
//public List<DotaHero> Players { get; set; }
public List<MyDotaClass.DotaHero> Players2 { get; private set; }
public MatchHistory() {
this.Players2 = new List<MyDotaClass.DotaHero>();
}
}
Note that I have also made the setter private here, as there should be no need to modify the value of this property after it's been initialized in the constructor.
It is look like your Players2 collection is not instantiated, so do it first:
this.Players2 = new List<MyDotaClass.DotaHero>();
and then you would be able to refer and use it:
_match.Players2.Add(_hero);
As for where to instantiate it, do it in the constructor of MatchHistory:
public MatchHistory() {
this.Players2 = new List<MyDotaClass.DotaHero>();
}
This is a good practice, because next time, even if you will forget to instantiate it, the constructor will do it automatically for you.
Otherwise, you'd keep getting: System.NullReferenceException
UPDATE:
You can't use this in a static context, change this method in order to enjoy from the constructor-base instantiating:
public static List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)
to this:
public List<MyDotaClass.MatchHistory> GetMatchHistory(string uri)
You initialized the MatchHistory instance but not the Players2 property so it's still null.
You probably want to allocate it in the constructor like this although there are other options;
public MatchHistory()
{
Players2 = new List<MyDotaClass.DotaHero>();
}
PS LoL > Dota :p
I have a couple of classes I'm having difficulty populating:
public class ta_Room
{
public string url { get; set; }
public double price { get; set; }
public string room_code { get; set; }
}
public class ta_Hotel2
{
public int hotel_id { get; set; }
public Dictionary<string, ta_Room> room_types { get; set; }
}
In my controller I have:
[HttpGet]
public ta_Hotel2 hotel_inventory() //int api_version, string lang)
{
{
ta_Room room = new ta_Room();
room.price = 23;
room.room_code = "1";
room.url = "http://www.nme.com";
ta_Hotel2 hotel = new ta_Hotel2();
hotel.room_types.Add("Single", room);
However I get a NullReferenceException on the last line above.
In the screenshot below, it shows both the hotel and room object have been created - can anyone please advise what I've done wrong please?
Thank you,
Mark
The error is due to the fact you are not building the instance of room_types inside ta_Hotel2. You should add a constructor as follows or just instantiate it within hotel_inventory():
public class ta_Hotel2
{
public int hotel_id { get; set; }
public Dictionary<string, ta_Room> room_types { get; set; }
public ta_Hotel2()
{
room_types = new Dictionary<string, ta_Room>();
}
}
Also note that, from an encapsulation point of view, I would also make the setter of room_types private after that. And, as a side note, I would also rename your classes and members as suggested here.
You cannot assign a value to hotel.room_types before you initialize. Like the way Efran suggest, use a public constructor in ta_Hotel2 class will solve your issue.
I have the following abstract class:
abstract class ContactQueue
{
public abstract DateTime period {
get; set; }
public abstract String type { get; set; }
public abstract String toString();
}
Now one of the sub classes of this class is the following:
class GeneralPercentageQueue : ContactQueue
{
public GeneralPercentageQueue(DateTime period)
{
this.period = period;
}
public int phone_answer_total {get; set;}
public int phone_answer_percentage_8025 { get; set; }
public int web_answer_percentage_8030 { get; set; }
public int web_answer_percentage_total { get; set; }
public int mail_answer_percentage { get; set; }
public override DateTime period { get; set; }
public override string type { get; set; }
public override string toString()
{
return period.ToString();
}
}
Now since i have several subclass of the abstract class i have created a list that can contain them all i want to loop through that list and access one of the specefic fields to do this i have attempted the following:
foreach(ContactQueue cq in p.GetGeneralEmailPercentageData(start,end))
{
foreach (ContactQueue contactqueue in finalDataList)
{
if (cq.period == contactqueue.period)
{
(GeneralPercentageQueue)contactqueue.mail_answer_percentage = (GeneralPercentageQueue)cq.mail_answer_percentage;
}
}
}
However im getting an error that there is no such field in the object ContactQueue
So how do i access it?
As others have mentioned you're missing parenthesis which is causing the error.
Instead you can use OfType(T) to filter the collections to only the type you want to compare.
foreach(GeneralPercentageQueue cq in p.GetGeneralEmailPercentageData(start,end)
.OfType<GeneralPercentageQueue>())
{
foreach (GeneralPercentageQueue contactqueue in finalDataList.OfType<GeneralPercentageQueue>())
{
if (cq.period == contactqueue.period)
{
contactqueue.mail_answer_percentage = cq.mail_answer_percentage;
}
}
}
This will prevent exceptions at runtime for mismatched types.
You need to add parentheses:
((GeneralPercentageQueue)contactqueue).mail_answer_percentage = ...;
You need to add paranthesis what is happening is the following:
contactqueue.mail_answer_percentage is calledcast is called on contactqueue.mail_answer_percentage to type GeneralPercentageQueue
Because the property mail_answer_percentage is not a property in type ContactQueue the first call fails, and you get the error that mail_answer_percentage isn't a property in ContactQueue
so your code should look like
((GeneralPercentageQueue)contactqueue).mail_answer_percentage =
((GeneralPercentageQueue)cq).mail_answer_percentage;
I'm trying to figure out what the proper syntax is to achieve a certain API goal, however I am struggling with visibility.
I want to be able to access a Messenger instance's member like msgr.Title.ForSuccesses.
However, I do not want to be able to instantiate Messenger.Titles from outside my Messenger class.
I'm also open to making Messenger.Titles a struct.
I'm guessing I need some sort of factory pattern or something, but I really have no idea how I'd go about doing that.
See below:
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this should be allowed
var t = new Messenger.Titles(); // this should NOT be allowed
}
}
public class Messenger {
// I've tried making this private/protected/internal...
public class Titles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
// I've tried making this private/protected/internal as well...
public Titles() {}
}
public Titles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
You just need to make Titles private and expose an interface instead of it.
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this is allowed
var t = new Messenger.Titles(); // this is NOT allowed
}
}
public class Messenger {
public interface ITitles {
string ForSuccesses { get; set; }
string ForNotifications { get; set; }
string ForWarnings { get; set; }
string ForErrors { get; set; }
}
private class Titles : ITitles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
}
public ITitles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
If you make the Titles constructor internal you will be able to create instances of it within your assembly only. If it is an API, perhaps that will be protected enough? You can see this pattern within the BCL (such as HttpWebRequest that can be created only through calls to WebRequest.Create).
Why Would I Ever Need to Use C# Nested Classes Nested type is never intended to be initialized from external type.
Well, you could make Titles a struct and make the constructor either public or internal. In that way, every time a client gets a copy of the Titles instance through the Title property, they will be getting the value, not the reference. They could modify that value, but to apply that change to the internal state of your object, they would need to be able to set the value back again through the Title property. They can't, because you have the Title setter marked private.
You will have to do the same when you change a value internally. For example:
// Your constructor...
public Messenger()
{
Titles t = new Titles();
t.ForSuccesses = "blah";
Title = t;
}
You can do this internally because you have access to the private setter for the Title property.
The main downside is that it might confuse the clients of your framework a bit because it looks like you can set the values of the Titles instance, but there is no real way for them to commit that change back to the Messenger class.