I am currently studying C# and am trying to prepare for next weeks lessons which will be the introduction of classes and methods. To that end i have attempted to build a class called MaxBox which is meant to be a general utility class that I can store some general functions in like 'Displaying a String' or 'Play Again'. I've built my main file (Program) and my class file (MaxBox) and lines #23, #28 and #59 return the same general error 'An object reference is required for the non-static field, method, or property 'program.MaxBox.DisplayStr(string)'. #57 returns a similar error 'An object reference is required for the non-static field, method, or property 'program.MaxBox.PlayAgain()'
I'm a total newb really, and i'm wrestling with objects, I've done some research to get myself this far but I don't understand the language enough yet to be able to understand what the resources I've read are saying I guess to solve this error. Help and guidance is greatly appreciated. I'm still in my first weeks and really I know nothing.
Program:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; // needed for close
using System.Threading.Tasks;
namespace a020_Breakcase_MeaningOfNames_C
{
class Program
{
public void Play()
{
/*
* Conditionals - Use switch/Case statement too:
* Evaluate user data (name)
* Return meaning of name evaluated
* OR
* Return 'Name not found' error message
* Say goodbye
*/
MaxBox.DisplayStr("What's in a name? Let's find out!");
Console.Write("\n\n");
do
{
MaxBox.DisplayStr("Enter Name: ");
string uName = Console.ReadLine().ToLower();
switch (uName)
{
case "doyle":
Console.WriteLine("Doyle means descendant of Dubhghalle");
break;
case "fiona":
Console.WriteLine("Fiona is considered to be a Latinised form of the Gaelic word fionn, meaning \"white\", \"fair\".");
break;
case "hunter":
Console.WriteLine("Hunter means to search with purpose");
break;
case "liam":
Console.WriteLine("This name is a short form of the Irish name Uilliam (William) which is now use independently as a given name. As a Hebrew name, Liam means \"my people; I have a nation\".");
break;
case "max":
Console.WriteLine("Short for of Maximilian, Maxwell, and the various name using it as a first syllable.");
break;
case "portia":
Console.WriteLine("It is of Latin origin. Feminine form of a Roman clan name. Portia was used by Shakespeare as the name of a clever, determined young heroine in \"The Merchant of Venice\" who disguises herself as a lawyer to save her husband's life.");
break;
default:
Console.WriteLine("I'm sorry but I don't know the meaning of the name " + uName + ".");
break;
}
} while (MaxBox.PlayAgain());
MaxBox.DisplayStr("C#eers!");
}
static void Main(string[] args)
{
Program myProgram = new Program();
myProgram.Play();
Console.Read();
}
}
}
My Class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace a020_Breakcase_MeaningOfNames_C
{
class MaxBox
{
/*
* MaxBox is my general functions class
* Contains
* DisplayStr() - Display the string given
* PlayAgain() - If True, runs program again
*/
public String uName;
public String command;
public void DisplayStr(String StrTxt)
{ Console.Write(StrTxt); }
public Boolean PlayAgain()
{
Console.Write("\n\nDo you want to play again? (y)es or (n)o: ");
String command = Console.ReadLine().ToLower().Trim();
if (command == "y" || command == "yes") return true;
return false;
}
}
}
MaxBox's methods are not static, you need an instance of it.
MaxBox maxBox = new MaxBox();
at the beginning of your main class. Then
maxBox.DisplayStr(....)
also, just to get you thinking, you can replace:
if (command == "y" || command == "yes") return true;
return false;
with
return (command == "y" || command == "yes");
The methods PlayAgain and DisplayStr are instance methods on the type MaxBox. In order to call them you need an instance of MaxBox on which to call them. Right now you are trying to call them via the type name which only works for static methods
MaxBox.DisplayStr("hello world"); // wrong
MaxBox mb = new MaxBox();
mb.DisplayStr("hello world"); // right
It is possible to define methods such that you can invoke them from the type name. But doing so requires that they be marked as static
class MaxBox {
public static void DisplayStr2(string str){ ... }
}
MaxBox.DisplayStr2("hello world"); // right
Related
Why when I type "gamble" the first time, only the if statement works? It's no use typing anything else, it still adds 10 woods. And why when I type anything else the first time, just the else statement works? It is no use typing "gamble, will continue saying " Write '' gamble '' to hit the tree. " PS: The variable its int = woods; and string gamble;
Console.WriteLine("You have {0} woods", woods);
Console.WriteLine("Write ''gamble'' to hit the tree");
gamble = Console.ReadLine();
bool loop = true;
while (loop)
{
if (gamble.Contains("gamble"))
{
woods = woods + 10;
Console.Clear();
}
else
{
Console.WriteLine("Write ''gamble'' to hit the tree");
}
Console.WriteLine("You have {0} woods", woods);
Console.ReadLine();
}
gamble = Console.ReadLine();
You only set gamble in the beginning. In the loop it is never changed. So it keeps using the first value over and over again.
Add gamble = to the last line of the loop.
If I understand what your are describing, you forgot to read into gamble again
Console.WriteLine("You have {0} woods", woods);
gamble = Console.ReadLine();
}
At the end of the while loop, you are doing Console.ReadLine() but not storing it. You need gamble = Console.ReadLine() to store the scanned string in the "gamble" variable.
Because loop is always true. You should change it to false after if and else statements...
The reason it's adding 10 wood regardless if there is something else than "gamble" in the console line, is because you're writing "gamble" in the returning message.
else {Console.WriteLine("Write ''gamble'' to hit the tree");} is the problem here.
You can fix it by either not writing the word "gamble" inside the returning message, or find a clever way to not have it run in a while(true) loop.
You can, for example, use the main method to have it run the function you're going to run just once.
Something like this.
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace ConsoleApp1
{
class Program
{
// Set a `wood` variable for the class.
protected int wood { get; set; }
static void Main(string[] args)
{
Program program = new Program(); // Making use of non-static methods.
program.Handler();
}
public void Handler()
{
Console.WriteLine("Write \"gamble\" to hit the tree.");
string message = Console.ReadLine();
if (message == "gamble")
{
addWood(); // Call the non-static method.
}
}
public bool addWood()
{
this.wood = this.wood + 10;
Console.WriteLine("You now have {0} wood!", this.wood);
Handler(); // Call the Handler() method again for infinite loop.
return true;
}
}
}
WARNING: The program will exit if there is something else than "gamble" written.
I have a public class, "CodeCompiler", which allows me to compile and run C# code at run-time. Just like IDEs work.
When I click the "button1" it creates code at run-time, compiles and executes.
My main Form1 contains a TextBox control called "textbox1". In order to make changes on that "textbox1" by runtime I made this button1_Click event.
But when I click it, it shows me a run-time error...
Compiler Errors :
Line 14,34 : An object reference is required for the non-static field, method, or property 'Compiling_CSharp_Code_at_Runtime.Form1.textBox1'
It showed me when I was editing the text data on that "textbox1". But if I will try to make changes about other property like "Size", "Location" then imagine what will happen!
using System;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace Compiling_CSharp_Code_at_Runtime
{
public class CodeCompiler
{
public CodeCompiler()
{
}
public object ExecuteCode(string code, string namespacename, string classname,
string functionname, bool isstatic,
string[] References1, params object[] args)
{
object returnval = null;
CompilerParameters compilerparams = new CompilerParameters();
for (int i = 0; i <= References1.GetUpperBound(0); i++)
{
compilerparams.ReferencedAssemblies.Add(References1[i]);
}
Assembly asm = BuildAssembly(code, compilerparams);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private Assembly BuildAssembly(string code, CompilerParameters compilerparams)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CodeCompiler cc = new CodeCompiler();
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2)
{
Compiling_CSharp_Code_at_Runtime.Form1.textBox1.Text += ""This is a DEMO "" st1 + st2.ToUpper();
}
}
}";
string namespace1 = "N1", class1 = "C1", function1 = "F1";
bool IsStatic = true;
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic, new string[] { "Compiling CSharp Code at Runtime.exe", "System.Windows.Forms.dll", "System.Drawing.dll", "System.ComponentModel.dll", "System.dll" }, "arg1", "arg2");
}
}
}
I found many problems related to this problem on this site where a suggestion was:
"It looks like I am calling a non static property from a static method.
I should either make the property static, or create an instance of Form1."
But even creation an instance of Form1 was difficult at runtime!
The problem appears to be that you're not passing reference to the Form1 on which you want code to be executed to CodeCompiler at all. The fact that you're calling it within your Form1 doesn't change anything - objects don't automatically learn anything about the object using them. (If they did, things would be a lot more complicated.)
The way you're accessing Form1 is also incorrect - you're using the typename (by the way, as a fully-qualified path which is pointless, because while the class C1 is not in the same namespace as Form1, you include Form1's namespace in the compiled code via using) to refer to a non-static member of the type. The instance member textBox1 of the type Form1 can be accessed only from some instance, but there's no logical way to access the Form1 object. What if you'd instantiated 10 of them? How would the decision be made which of those 10 to return to your call?
What you should do, if you want to continue down this path (and I'm not really sure why you're trying to mimic eval() in C# - you're throwing away a lot of the safety that makes C# nice and easy to work with), is pass a reference to the Form1 instance you want altered either in the constructor of CodeCompiler or in the ExecuteCode method. I think the latter would probably make more sense.
You should change your SourceCode1 so that it looks like this (this also fixes a typo in the original code, restoring a missing + character):
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2, Form1 formToExecuteOn)
{
formToExecuteOn.textBox1.Text +=
""This is a DEMO "" + st1 + st2.ToUpper();
}
}
}";
Then call the ExecuteCode() method like this:
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic,
new string[] { "Compiling CSharp Code at Runtime.exe",
"System.Windows.Forms.dll", "System.Drawing.dll",
"System.ComponentModel.dll", "System.dll" },
"arg1", "arg2", this);
This will compile the code such that the Form1 instance to be used can be passed to the method when it's invoked. And the reference to that Form1 instance is provided in the argument list that is actually passed for the method invocation (i.e. the last argument, this)..
Granted, even if that works, it'll only allow you to execute code on Form1 objects. The greater point of this is that if you're going to go down this path, you need to be passing reference to anything you want altered to CodeCompiler somehow. I'm not sure whether object objectToChange would work instead of formToChange, and how much information the compiler is going to need about the object you're passing in order to execute code on it.
And once more, for feeling: you need a very, very unique use case to make any of this even remotely a good use of time or sanity. (You have to pass seven precisely-constructed objects, mostly strings, to ExecuteCode() every single time you want to run anything!)
I've recently written this short application in C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Checker
{
class Program
{
static void Main(string[] args)
{
Properties.Settings.Default.Save();
Program re = new Program();
re.next();
}
public void next()
{
Console.WriteLine("Have you already entered name?");
int ch = int.Parse(Console.ReadLine());
if (ch == 0)
{
Console.WriteLine("What is your name?");
String name = Console.ReadLine();
Console.WriteLine("Thank you!");
Console.ReadKey();
}
Console.WriteLine("Your name is " + name);
}
}
}
Now, I've created a settings file, and created a "name" variable there, with the "String" type.
The scope of it is "User".
So I want it to load the "name" variable with the properties line, but I can't even compile the program because of this error:
Error 1 The name 'name' does not exist in the current context
How can I solve it?
The answer to your problem becomes a little more apparent when you indent:
String name;
if (ch == 0)
{
Console.WriteLine("What is your name?");
name = Console.ReadLine();
Console.WriteLine("Thank you!");
Console.ReadKey();
}
else
{
name = Settings.Default.name;
}
Console.WriteLine("Your name is " + name);
Now you can see that you defined a String called name inside the if-block, thus using it in the Console.WriteLine outside the if-block is out of scope! Move that last Console.WriteLine inside the if-block to solve the scoping issue.
Edit: Based on your comment, your code needs a bit more logic to attain what you're trying to do. I updated my snippet above to accomplish what I think you're trying to do.
You declared that variable inside the if block.
As the compiler is trying to tell you, it doesn't exist outside that block.
If you want to use your Settings class, write Settings.Default.Name.
Your intentions are a bit unclear, but to me it seems as though you are trying to have the application display the name of the user if it has already been saved or ask for it if it hasn't. If that is the case, something like this should work:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Checker
{
class Program
{
static void Main(string[] args)
{
Program re = new Program();
re.next();
Properties.Settings.Default.Save();
}
public void next()
{
String name = Settings.Default.name;
if (String.IsNullOrEmpty(name))
{
Console.WriteLine("What is your name?");
name = Console.ReadLine();
Settings.Default.name = name;
Console.WriteLine("Thank you!");
Console.ReadKey();
}
else
{
Console.WriteLine("Your name is " + name);
}
}
}
}
In your OP, your settings were not being saved before the program exited nor were you setting the name property.
In my "LuaTest" namespace I have a class called "Planet". The C# code reads like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Planet
{
public Planet(string name)
{
this.Name = name;
}
public Planet() : this("NoName") { }
public string Name
{
get;
private set;
}
public void printName()
{
Console.WriteLine("This planet's name is {0}", Name);
}
}
}
Then I built LuaTest.dll and copied this file to the same folder where my Lua script is saved. In the Lua script I wrote:
--define Path for required dlls
package.cpath = package.cpath .. ";" .. "/?.dll"
package.path = package.path .. ";" .. "/?.dll/"
require 'luanet'
luanet.load_assembly("LuaTest")
local Planet = luanet.import_type("LuaTest.Planet")
local planet = Planet("Earth")
planet.printName()
However, this piece of code does not work. Lua interpreter throws this error:
lua: dllTest.lua:7: attempt to call local 'Planet' (a nil value)
I suspect that my LuaTest assembly is not loaded at all. Could anyone point out where I did wrong? I would very much appreciate it, since I've been stuck by this problem for days.
Also it might be helpful to add that my LuaInterface.dll is the rebuilt version in .NET4.0 environment.
So I spent a LOT of time similarly. What really drove me bonkers was trying to get Enums working. Eventually I ditched my project for a very simplified console application, very similar (ironically also named 'LuaTest').
Edit: I've noted that the initial "luanet.load_assembly("LuaTest")" appears superfluous. Works with it, or surprisingly without it.
Another Edit: As in my badly edited comment below, when I removed:
print(luanet.LuaTest.Pointless)
It all stopped working (LuaTest.Pointless became nil). But adding the luanet.load_assembly("LuaTest") then makes it work. It may be that there is some sort of odd implicit load in the print or in just expressing they type. Very Strange(tm).
In any case, it seems to work for me (note: after a lot of experimentation). I don't know why yours is failing, I don't note any real difference, but here's all my code in case someone else can spot the critical difference:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Program
{
static void Main(string[] args)
{
Lua lua = new Lua();
lua.DoFile("test.lua");
}
public int some_member = 3;
}
public class Pointless
{
public enum AnEnum
{
One,
Two,
Three
};
public static string aStaticInt = "This is static.";
public double i;
public string n = "Nice";
public AnEnum oneEnumVal = AnEnum.One;
private AnEnum twoEnumVal = AnEnum.Two;
private string very;
public Pointless(string HowPointLess)
{
i = 3.13;
very = HowPointLess;
}
public class MoreInnerClass
{
public string message = "More, please!";
}
public void Compare(AnEnum inputEnum)
{
if (inputEnum == AnEnum.Three)
Console.WriteLine("Match.");
else
Console.WriteLine("Fail match.");
}
}
}
and test.lua:
luanet.load_assembly("LuaTest")
--Pointless is a class in LuaTest assembly
local Pointless = luanet.import_type("LuaTest.Pointless")
print(Pointless)
--Gives 'ProxyType(LuaTest.Pointless): 46104728
print(Pointless.aStaticInt)
--'This is static.'
--Fails if not static, as we expect
--Instantiate a 'Pointless'.
local p = Pointless("Very")
print(p)
--Gives 'LuaTest.Pointless: 12289376'
--Now we can get at the items inside the Pointless
--class (well, this instance, anyway).
local e = p.AnEnum;
print(e)
--ProxyType(LuaTest.Pointless+AnEnum): 23452342
--I guess the + must designate that it is a type?
print(p.i)
--3.14
print(p.oneEnumVal)
--Gives 'One: 0'
print(p.twoEnumVal)
--Gives 'twoEnumVal'... private
--behaves very differently.
print(e.Two:ToString())
--Gives 'Two'
local more = p.MoreInnerClass()
print(more.message)
--'More, Please!'
--create an enum value here in the script,
--pass it back for a comparison to
--the enum.
local anotherEnumVal = p.AnEnum.Three
p:Compare(anotherEnumVal)
--outputs 'Match'
Having spent the last several days working on a project that required this exact functionality from LuaInterface, I stumbled across a piece of Lua code that turned out to be the perfect solution (see Reference 1). Whilst searching for this solution, I noticed this question and figured I'd drop my two cents in.
To apply this solution, I merely run the CLRPackage code while initializing my LuaInterface Lua object. However, the require statement works just as well.
The code provided in reference 1 allows the use of import statements, similar to C# using statements. Once an assembly is imported, its members are accessible in the global namespace. The import statement eliminates the need to use load_assembly or import_type (except in situations in which you need to use members of the same name from different assemblies. In this scenario, import_type would be used similar to C# using NewTypeName = Assembly.OldTypeName).
import "LuaTest"
planet = Planet("Earth")
planet:printName()
This package also works great with enums!
Further information regarding the use of this package may be found at Reference 2.
Hope this helps!
Reference 1: https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua
Reference 2: http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/
I spent some time in binding C# dll to lua. Your posts were helpful but something was missing. The following solution should work:
(Make sure to change your compiler to .NET Framework 3.5 or lower!)
Planet.dll:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Planets
{
public class Planet
{
private string name;
public string Name
{
get { return name; }
set { this.name = value; }
}
private float diameter;
public float Diameter
{
get { return diameter; }
set { this.diameter = value; }
}
private int cntContinents;
public int CntContinents
{
get { return cntContinents; }
set { this.cntContinents = value; }
}
public Planet()
{
Console.WriteLine("Constructor 1");
this.name = "nameless";
this.diameter = 0;
this.cntContinents = 0;
}
public Planet(string n, float d, int k)
{
Console.WriteLine("Constructor 2");
this.name = n;
this.diameter = d;
this.cntContinents = k;
}
public void testMethod()
{
Console.WriteLine("This is a Test!");
}
}
}
Use the code above, paste it into your class library project and compile it with .NET smaller or equal 3.5.
The location of the generated DLL needs to be known by the lua enviroment. Paste it e.g at "clibs"-folder or another well known lua system path. Then try to use the following lua example. It should work.
Test1.lua: (Option 1 with "import" from CLRPackage)
require "luanet"
require "CLRPackage"
import "Planet"
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
Test2.lua: (Option 2 with "load_assembly")
require "luanet"
require "CLRPackage"
luanet.load_assembly("Planet")
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
In both cases the console output will look like this:
ProxyType(Planets.Planet): 18643596
Constructor 1
Planets.Planet: 33574638
Constructor 2
nameless
Mars
Planet Earth is my home planet. Its diameter is round about 12742km. Our neighbour is Mars
I hope its helps some of you.
Edit 1:
by the way, a method call from lua looks like this:
PlanetObject1:testMethod()
PlanetObject2:testMethod()
Edit 2:
I found different dll's whitch needed to be handled differently. One needed the "import"-function and another needed the "load_assembly"-function. Keep that maybe in mind!
I am having fun with a couple of errors I am getting in a C# application I am writing.
The error I keep getting is:
encrypt and decrypt calls must have a return type
Console.WriteLine being used as a method
static void encrypt(string[] args) expected class, delegate, interface or struct
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string pw ="", hash =""; //Declare an intialise variables
if (args.Length < 4) // Test to see if correct number of arguments have been passed
{
Console.WriteLine("Please use command line arguments in this format: encrypt -e (or -d) password-to-encrypt-with input-file output-file");
Environment.Exit(0);
}
if (args[1].Length < 10 || args[1].Length > 40) // Test to see if the password is between 10 and 40 characters
{
Console.WriteLine("Please use a password between 10 and 40 characters");
Environment.Exit(0);
}
switch (args[0]) //Uses first argument value to drive switch statement (-e or -d)
{
case "-e":
encrypt(string[] args);
break;
case "-d":
decrypt(string[] args);
break;
default:
Console.WriteLine("When using the program please use -e to encrypt and -d to decrypt");
break;
}
} //End of MAIN
static void encrypt(string[] args) //Function to encrypt
{
string inputtext =""; //Initialise Varible (Ensure it is empty)
inputtext=System.IO.File.ReadAllText(args[2]); //Read file in an assign to input text
return;
}
static void decrypt(string[] args) //Function to decrypt
{
string inputtext =""; //Initialise Varible (Ensure it is empty)
inputtext=System.IO.File.ReadAllText(args[2]); //Read file in an assign to input text
return;
}
}
}
Any help would be much appreciated!
Alistair
When calling a method, you must not specify the types of the arguments. So:
case "-e":
encrypt(args);
break;
Along with what Hans has said, you mentioned an error about return types in your methods.
Your encrypt and decrypt methods have return statements, but they are void methods meaning they don't have any return types.
Either give it a type you want to return (presumably the string you are manipulating) or just remove the return statement altogether. You do not need to explicitly put return at the end of a method to get it to exit out of the method. It will do that anyway.
Two small pro-tips, I would declare your fields on different lines, not all bunched together (with the way you have declared pw and hash) and also add a using directive for System.IO, so you don't have to call System.IO.File.ReadAllText, you can just call File.ReadAllText.