Property is null, even after being set in code - c#

I've been trying to solve this for ages (3 days) now and I just cannot figure it out. I will try to explain the problem comprehensively because it is a bit more complex.
My school assignment is to create a simple text game using OOP in C# Visual Studio 2008 (should be built on a library the teacher provided for us). It should only use console. I have a decent experience with OOP from PHP and C++ but I still cannot figure this out.
80% of the text game is already working so I won't bore you with classes and stuff that already works and is not related to the problem. Ok let's get started:
Each command in the game (what you can type into the console and hit enter) is represented by a single class both extending an abstract class and an interface from the library I am supposed to built the game on. Bellow is a class Use which represents a command for using items (e.g. you type "use sword" into the console and the game will look for an item called sword and call its use method):
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Game.Commands
{
class Use : TextGame.Commands.ACommand, TextGame.Commands.ICommand
{
private string name;
public new string Name
{
set { this.name = value; }
get { return this.name; }
}
private string description;
public new string Description
{
set { this.description = value; }
get { return this.description; }
}
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
public Use(string name, string description) : base(name, description)
{
this.name = name;
this.description = description;
}
private TextGame.Core.GameState gameState;
public TextGame.Core.GameState Execute(TextGame.Core.IGame game)
{
// This is just a test because it appears the problem is
// with the parameters property. There should be a command
// you have typed in the console but its always null
// Note that I have not yet coded the body of this method.
// I will do that once I solve the problem.
if (this.parameters == null)
{
Console.WriteLine("is null");
}
else
{
Console.WriteLine(this.parameters);
}
return this.gameState;
}
}
}
There are two other classes that are used. The Parser class and the Game class. There are a bit longer so I will only post snippets of relevant stuff from them. Parser class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections; // ArrayList, Dictionary, Hashtable
using System.Text.RegularExpressions; // regex engine
using Game.Commands;
namespace Game
{
class Parser
{
private ArrayList commands = new ArrayList();
// All commands that are available in the game so far are
// initialized here in the constructor (and added to the arraylist)...
// skip to the other method this is not important
public Parser()
{
this.commands.Add(new North("^north", "Go north"));
this.commands.Add(new South("^south", "Go south"));
this.commands.Add(new East("^east", "Go east"));
this.commands.Add(new West("^west", "Go west"));
this.commands.Add(new Use("^use\\s\\w+", "Try to use the selected item"));
this.commands.Add(new Quit("^quit", "Quit the game"));
}
// This method takes as an argument a string representing
// a command you type in the console. It then searches the arraylist
// via the regex. If the command exists, it returns an the command object
// from the arraylist
// This works fine and returns right objects (tested)
public TextGame.Commands.ACommand GetCommand(string command)
{
TextGame.Commands.ACommand ret = null;
foreach (TextGame.Commands.ACommand c in this.commands)
{
Regex exp = new Regex(#c.Name, RegexOptions.IgnoreCase);
MatchCollection MatchList = exp.Matches(command);
if (MatchList.Count > 0)
{
ret = c;
}
}
return ret;
}
}
}
Now a snippet from the Game class where I'm using both above classes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TextGame.Core;
using System.Collections;
using Game.Items;
using Game.Commands;
namespace Game
{
class Game : TextGame.Core.IGame
{
public void Play()
{
// Here I read commands from the console in a loop and
// call the ProcessCommand() method. No problem here.
while (true)
{
string command = Console.ReadLine();
this.ProcessCommand(command);
}
}
// This is the IMPORTANT method so take a closer look
private TextGame.Core.GameState gameState;
public TextGame.Core.GameState ProcessCommand(string command)
{
Parser parser = new Parser();
TextGame.Commands.ACommand c = parser.GetCommand(command);
if (c != null)
{
// HERE I ADD THE COMMAND FROM THE CONSOLE TO THE C OBJECT
// I ADD IT VIA THE SETTER TO THE PARAMETERS PROPERTY
// OF THE COMMAND
c.Params = command;
// AND I CALL THE COMMAND'S EXECUTE() METHOD - SEE THE FIRST CLASS -
// USE - WHERE I TEST FOR THE PARAMS PROPERTY BUT IT IS STILL NULL
this.gameState = ((TextGame.Commands.ICommand)c).Execute(this);
}
}
}
}
I have added comments to the snippets to describe where is the problem. I hope I have explained it well.
Anyone has any ideas? I've been working on this projects for about 3 weeks now and most of the stuff went smoothly when 3 days ago I came across this problem and since then I've been trying to get my head around this problem.

Your problem is with the 'new' keyword. Here's where you're using it in the 'Use' class:
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
You're creating a different property that just happens to have the same name as a property on the type you are inheriting from. The 'new' keyword tells the compiler you meant to do that.
Basically, this means that if you do the following:
var x = new Use();
x.Params = "abcd";
((ACommand)x).Params = "wxyz";
Console.Writeline("direct: " + x.Params);
Console.Writeline("ACommand: " + ((ACommand)x).Params);
You'll get this output:
direct: abcd
ACommand: wxyz
You probably want to remove the definition of 'Params' entirely from Use and just inherit the one from ACommand. Probably from Name and Description as well, but you should be able to figure out from here if you want that or not.

Without seeing the code for the ACommand class... Try removing the "new" operator in the Params declaration of the Use class. When your setting the property c.Params = command; is actually setting the property of the base class, in the Execute method your checking this.parameters instead of base.Params.

// This is just a test because it appears the problem is
// with the parameters property. There should be a command
// you have typed in the console but its always null
// Note that I have not yet coded the body of this method.
// I will do that once I solve the problem.
This is caused by you declaring new on your properties. These should be override, or not included at all if you don't need to change the logic of ACommand.
When you reference as an ACommand:
TextGame.Commands.ACommand c = parser.GetCommand(command);
c.Params = command;
You will use either ACommand's Params, or your overrides (if you had defined one).
Your new Params shadow ACommand's Params, and are only accessible if your reference is a UseCommand.

Your problem is here:
private string parameters;
public new string Params
{
set { this.parameters = value; }
get { return this.parameters; }
}
In your code:
c.Params = command;
you are referencing the type TextGame.Commands.ACommand. Because you're hiding the Param property in your subclass, you're causing a non-polymorphic reference. Remove the definition above and rely on the base class definition of Param, and you'll be fine.

It's been a while since I ran into this problem, but if you open that up in Reflector I expect you will see that you are hiding the Use.Params property behind a callvirt explicitly bound to its base type there.... as the faster typists pointed out.

Related

Difficulty regarding passing constructor parameters

This is an assignment for a class.
Here is my code so far.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Proj03
{
class MyClass
{
public string MyClass(bool First, int Last)
{
if (First == true)
{
return "FirstName";
}
else if (Last == 3)
{
return "LastName";
}
}
}
class Program
{
static void Main(string[] args)
{
bool var1 = true;
int var2 = 3;
Console.WriteLine(new MyClass(var1)); //Line 34
Console.WriteLine(new MyClass(var2)); //Line 35
Console.WriteLine("Press any key to terminate.");
Console.ReadKey();
}//end main
}//end class Program
}//end namespace
The problem I'm having is twofold:
First, the error on line 34 and 35 keeps saying that there is no constructor in "MyClass" that takes one argument. So it's easy to deduce that, wow, I need a constructor that can take one argument in the class. I can make the constructor just fine, but the difficulty is in passing the "var1" and "var2". I believe I need to pass by reference here.
Secondly, I believe I need to take into consideration the fact that "var1" and "var2" are different variable types. This I really don't know what to do about. But the main question of this post is figuring out the first problem.
The limitation put on us by the instructor is that we are not allowed to change anything within the "Program" class.
The required output is as follows:
Display your first name here
Display your last name here
Press any key to terminate.
You can address the missing constructor issue like this:
public MyClass(bool First)
{
// your code here
}
public MyClass(int Last)
{
// your code here
}
Note that there is no return type specified, as constructors don't have returns. This will allow your constructor calls to run successfully.
I probably shouldn't be doing that, but, well... is this what you're trying to achieve?
class MyClass
{
private bool? _first;
private int? _last;
public MyClass(bool first)
{
_first = first;
}
public MyClass(int last)
{
_last = last;
}
public override string ToString()
{
if (_first != null)
return "FirstName";
if (_last != null)
return "LastName";
return String.Empty;
}
}
The problem is arising from the fact that you have your class name and method named the same. You cannot do this. Any properties or methods in your class must not be called the same as your class.
Your constructor issue is due to you calling new MyClass(var1). You did not specify a constructor in your class. That would look something like this:
public class MyClass
{
// This is a constructor that takes a parameter.
public MyClass(string myString)
{
}
// This is a constructor that takes 0 parameters.
// This exists if you do not specifically declare a constructor.
public MyClass()
{
}
}
What you are looking for here is called constructor overloading. You should make one constructor that accepts a bool as an argument and another that accepts an int.
It is a homework assignment, so I am not going to provide a sample. However, that should be enough to get you started.
Good luck.
Have a look at optional arguments. Using them, you could assign the arguments in the constructor default values (different from what will be sent by the program). Then, your program can send over either variable type and no error will be thrown regarding incorrect number of arguments or variable types.

Predefined macros for method names

In C++ there are predefined macros such as __FUNCTION__, which compile to a string literal of the function name the macro is used in.
void MyFunc()
{
printf("I'm in %s!", __FUNCTION__); // I'm in MyFunc!
}
Is there anything similar for C#? I am looking to do this for asp.net web forms:
public string MyProperty
{
get { return (string)ViewState[__PROPERTY__]; }
set { ViewState[__PROPERTY__] = value; }
}
Obviously this doesn't work (otherwise I wouldn't ask the question), I would like to know if there's something similar in C# that doesn't use reflection or have any negative performance impacts versus using a string literal "MyProperty".
This will hopefully cut down on typos on my end, but I can think of a few other instances where this would be useful.
C#'s preprocessor doesn't support macros with associated values like C++, but what you're trying to do can be done with compilers that support C# 5.0 and greater (so at least VS2012+) through compiler generated Caller Information. Specifically, via the CallerMemberNameAttribute from the System.Runtime.CompilerServices namespace. Based on your question's code, I created the following example to illustrate how you could go about doing what you want to do:
using System;
class ViewState
{
public string this[string propertyName]
{
get { return propertyName; }
set { }
}
};
class View
{
ViewState mState = new ViewState();
static string GetCallerName(
[System.Runtime.CompilerServices.CallerMemberName] string memberName = "")
{
return memberName;
}
public string MyProperty
{
get { return (string)mState[GetCallerName()]; }
set { mState[GetCallerName()] = value; }
}
};
class Program
{
static void Main(string[] args)
{
var view = new View();
Console.WriteLine(view.MyProperty);
Console.ReadKey();
}
};
"MyProperty" will be printed to the console. When compiling, the compiler will replace the default value of GetCallerName's memberName argument with the the calling construct's (property, method, etc) name. So there's no code maintenance needed by the programmer
It should also be noted that this has the added benefit of being able to play nice with obfuscation tools, so long as they happen post-compilation.
You could use the StackTrace and StackFrame to get the name of the current method
StackTrace st = new StackTrace();
StackFrame sf = st.GetFrame(1);
string method = sf.GetMethod().ToString();
For properties, the returned method name will include the magic get_ or set_ prefixes.
However, I don't think you can really refactor this into an inline macro or function like you could in C++. But if you do refactor a utility method to DRY this out, you could probably just pop the StackTrace back one step to log the caller's information?
I don't know if there is something like a ViewBag in ASP.NET WebForms. Just in case there isn't, it isn't to difficult to roll you own. You can then wrap the ViewState in that class and get regular property member access like you wish.
public class ExpandoViewState : DynamicObject
{
private readonly StateBag _viewState;
public ExpandoViewState(StateBag viewState)
{
_viewState = viewState;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = _viewState[binder.Name];
if (result != null)
return true;
return base.TryGetMember(binder, out result);
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
_viewState[binder.Name] = value;
return true;
}
}
...
dynamic state = new ExpandoViewState(ViewState);
var val = (string)state.MyProperty;
state.MyProperty = "hi";

C# Get property value without creating instance?

Is it possible to get value without creating an instance ?
I have this class:
public class MyClass
{
public string Name{ get{ return "David"; } }
public MyClass()
{
}
}
Now I need get the value "David", without creating instance of MyClass.
Real answer: no. It's an instance property, so you can only call it on an instance. You should either create an instance, or make the property static as shown in other answers.
See MSDN for more information about the difference between static and instance members.
Tongue-in-cheek but still correct answer:
Is it possible to get value without creating an instance ?
Yes, but only via some really horrible code which creates some IL passing in null as this (which you don't use in your property), using a DynamicMethod. Sample code:
// Jon Skeet explicitly disclaims any association with this horrible code.
// THIS CODE IS FOR FUN ONLY. USING IT WILL INCUR WAILING AND GNASHING OF TEETH.
using System;
using System.Reflection.Emit;
public class MyClass
{
public string Name { get{ return "David"; } }
}
class Test
{
static void Main()
{
var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
var dynamicMethod = new DynamicMethod("Ugly", typeof(string),
Type.EmptyTypes);
var generator = dynamicMethod.GetILGenerator();
generator.Emit(OpCodes.Ldnull);
generator.Emit(OpCodes.Call, method);
generator.Emit(OpCodes.Ret);
var ugly = (Func<string>) dynamicMethod.CreateDelegate(
typeof(Func<string>));
Console.WriteLine(ugly());
}
}
Please don't do this. Ever. It's ghastly. It should be trampled on, cut up into little bits, set on fire, then cut up again. Fun though, isn't it? ;)
This works because it's using call instead of callvirt. Normally the C# compiler would use a callvirt call even if it's not calling a virtual member because that gets null reference checking "for free" (as far as the IL stream is concerned). A non-virtual call like this doesn't check for nullity first, it just invokes the member. If you checked this within the property call, you'd find it's null.
EDIT: As noted by Chris Sinclair, you can do it more simply using an open delegate instance:
var method = typeof(MyClass).GetProperty("Name").GetGetMethod();
var openDelegate = (Func<MyClass, string>) Delegate.CreateDelegate
(typeof(Func<MyClass, string>), method);
Console.WriteLine(openDelegate(null));
(But again, please don't!)
You can make that property static
public static string Name{ get{ return "David"; } }
Usage:
MyClass.Name;
You requirements do seem strange, but I think you're looking for some kind of metadata. You can use an attribute to achieve this:
public class NameAttribute : Attribute {
public string Name { get; private set; }
public NameAttribute(string name) {
Name = name;
}
}
[Name("George")]
public class Dad {
public string Name {
get {
return NameGetter.For(this.GetType());
}
}
}
[Name("Frank")]
public class Son : Dad {
}
public static class NameGetter {
public static string For<T>() {
return For(typeof(T));
}
public static string For(Type type) {
// add error checking ...
return ((NameAttribute)type.GetCustomAttributes(typeof(NameAttribute), false)[0]).Name;
}
}
Now this code can get names with and without instances:
Console.WriteLine(new Dad().Name);
Console.WriteLine(new Son().Name);
Console.WriteLine(NameGetter.For<Dad>());
Console.WriteLine(NameGetter.For<Son>());
You can make your property static, as pointed out by many others.
public static string Name{ get{ return "David"; } }
Be aware that this means your instances of MyClass will no longer have their own Name property, since static members belong to the class, not the individual object instances of it.
Edit:
In a note, you mentioned that you want to override the Name property in subclasses. At the same time, you want to be able to access it at the class level (access it without creating an instance of your class).
For the static properties, you would simply create a new Name property in each class. Since they are static, you're always (almost always, yay reflection) going to access them using a specific class, so you'd be specifying which version of Name you want to get. If you want to try and hack polymorphism in there and get the name from any given subclass of MyClass, you could do so using reflection, but I wouldn't recommend doing so.
Using the example from your comment:
public class Dad
{
public static string Name { get { return "George"; }
}
public class Son : Dad
{
public static string Name { get{ return "Frank"; }
}
public static void Test()
{
Console.WriteLine(Dad.Name); // prints "George"
Console.WriteLine(Son.Name); // prints "Frank"
Dad actuallyASon = new Son();
PropertyInfo nameProp = actuallyASon.GetType().GetProperty("Name");
Console.WriteLine(nameProp.GetValue(actuallyASon, null)); // prints "Frank"
}
As a side note, since you are declaring a property that has only a getter and it is returning a constant value, I recommend possibly using a const or static readonly variable instead.
public const string Name = "David";
public static readonly string Name = "David";
Usage for both would be the same:
string name = MyClass.Name;
The main benefit (and drawback) of const is that all references to it are actually replaced by its value when the code is compiled. That means it will be a little faster, but if you ever change its value, you will need to recompile ALL code that references it.
Whenever you write C# code, always check if your method and property getter/setter code does anything at all with other instance members of the class. If they don't, be sure to apply the static keyword. Certainly the case here, it trivially solves your problem.
The reason I really post to this question is that there's a bit of language bias at work in some of the answers. The C# rule that you can't call an instance method on a null object is a specific C# language rule. It is without a doubt a very wise one, it really helps to troubleshoot NullReferenceExceptions, they are raised at the call site instead of somewhere inside of a method where it gets very hard to diagnose that the this reference is null.
But this is certainly not a requirement to the CLR, nor of every language that run on the CLR. In fact, even C# doesn't enforce it consistently, you can readily bypass it in an extension method:
public static class Extensions {
public static bool IsNullOrEmpty(this string obj) {
return obj != null && obj.Length > 0;
}
}
...
string s = null;
bool empty = s.IsNullOrEmpty(); // Fine
And using your property from a language that doesn't have the same rule works fine as well. Like C++/CLI:
#include "stdafx.h"
using namespace System;
using namespace ClassLibrary1; // Add reference
int main(array<System::String ^> ^args)
{
MyClass^ obj = nullptr;
String^ name = obj->Name; // Fine
Console::WriteLine(name);
return 0;
}
Create a static property:
public class MyClass
{
public static string Name { get { return "David"; } }
public MyClass()
{
}
}
Get it like so:
string name1 = MyClass.Name;
That is not possible. As Name is an instance property, you can only get its value if you have an instance.
Also, note that you are not talking about a parameter, but about a property.
Create a static class or a static property, and you don't have to explicitly instantiate it.

Using methods from another class in forms, C#

Thank you very much for the response. I have edited my post to show the QuoteMgr class. I use this mostly to read and save quotes to file; it is read back into an array of quotes called mylist. I can't figure out how to call QuoteMgr methods from within all of the four forms I have created. The only way I have found is to instantiate QuoteMgr from within one of the forms, but that won't work for the other three forms. The method I want to use in different forms is getRandomQuote() - haven't written the other methods yet.
My plan was to read data from a file, display the quote on the main form, and offer choice to add more quotes, edit one, or display another quote. A different form would be displayed, appropriate to the choice made.
At heart the problem is I don't fully grasp OOP. I understand the idea of having an abstract class to inherit methods from. If I do this, will the different forms be able to access my array of quotes ("mylist")? For data integrity, I think I only want one instance of my data floating around. In which case, I could have an abstract class with all of the quote manipulation methods, and use QuoteMgr only to read/write to file.
From the standpoint of learning the right way to program, is this the right design?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;
namespace Quote
{
class QuoteMgr
{
Quotes myquote = new Quotes();
Quotes objectToSerialize = new Quotes();
Serializer serializer = new Serializer();
string myFile = "H:\\Dad\\Quotes\\quotes.quo";
public QuoteMgr()
{
}
static Random r = new Random();
public void getFile()
{
//fills myquote.mylist with quote strings from file
if (File.Exists(myFile))
{
objectToSerialize = serializer.DeSerializeObject(myFile);
myquote.myList = objectToSerialize.QuoteList;
//myquote.ShowQuotes();
}
else
{
FileInfo makeFile = new FileInfo(#myFile);
makeFile.Create();
}
}//end of get file
public void saveFile()
{
objectToSerialize.QuoteList = myquote.myList;
serializer.SerializeObject(myFile, objectToSerialize);
}
public string getRandomQuote()
{
int x = myquote.myList.Count-1;
return myquote.myList[r.Next(x)];
}
public void GUIop()
{
getFile();
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Form1 myMainScreen = new Form1();
//make all other forms invisible
myMainScreen.Visible = true;
changeQuoteDisplayed(myMainScreen);
Application.Run(myMainScreen);
saveFile();
}
public void changeQuoteDisplayed(Form1 theForm)
{
string s;
s = getRandomQuote();
theForm.lblDisplayQuote.Text = s;
}
}
}
It sounds like you should move the changeQuoteDisplayed method into your Form class...it doesn't make any sense to call a method in another class with your Form as an argument, only to have the other class modify the form you passed it. For one, you should not have public UI components inside your Form..if you must modify these from outside the form, make their data accessible through Properties.
If this is a method that all of your forms need to use, then perhaps you should allow them to inherit it through an abstract class, providing an abstract property as well that your child classes will use to implement set, making it update whatever UI component the child class needs updated on that method call. It could look something like this:
public abstract class QuoteBase
{
protected void changeQuoteDisplayed()
{
string s;
s = getRandomQuote();
LabelText = s;
// theForm.lblDisplayQuote.Text = s;
}
public abstract String LabelText
{
get; set;
}
}
public class EditQuote : QuoteBase
{
public override String LabelText
{
get { return lblDisplayQuote.Text; }
set { lblDisplayQuote.Text = value; }
}
}
Now all you need to do is implement the LabelText property in all of your Quote classes to update whatever label you want without needing to send an instance of your form to some other class to get an update.
Of course, this is just a wild guess..it's hard to tell what you should actually do without more information.

How to use the same info across multiple forms

I am working on my first C# program and have run into a brick wall. I want to be able to set and get variables throughout diferent forms in the same application.
I created a class called "data" which contains the following:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Application1
{
public class data
{
public string SearchAirport
{
get
{
return searchairport;
}
set
{
searchairport = value;
}
}
}
}
What do I need to put into my forms to be able to use this class??
Right now all I have is:
data.SearchAirport = commandAirport;
string working = data.SearchAirport;
I know I have to add something else to keep from getting the:
"Error 11 An object reference is required for the non-static field, method, or property 'Sector_Datastore_2._0.data.SearchAirport.get'..."
error
Well, you need to declare searchairport:
public class data
{
private string searchairport;
public string SearchAirport
{
get
{
return searchairport;
}
set
{
searchairport = value;
}
}
}
alternatively, you could let C# do that automatically by using the following code:
public class data
{
public string SearchAirport
{
get;
set;
}
}
You are accessing searchAirport statically, and the method itself is not static.
You can either add the static keyword to the SearchAirport method signature or create a data object and then call SearchAirport on that object.
I'd suggest a Service Locator pattern, but I'm afraid it's way too complicated for what the Question-poster wants to achieve.
Just in case it may be useful later on: Service Locator pattern
data d = new data();
....before those lines

Categories

Resources