data structure of objects and methods in c# - c#

I am new to c# and fairly new to programming. I need help with a topic which i have been trying to figure out from the past week. I have 3 files:
Control: this is an interface and should contain the list of my
methods
ControlImpl : this the implementaion of the interfaces.
Runtime: contains which the binding code between the main method
and the interface implementaion
Test_main: from where i call the
runtime method 'call'
Problem: there can be any number of instances(for ex: c, c1, c2, etc) in Control file and each instance should be able to call SetTime() and Nop() methods.
I made a list of the methods SetTime() and Nop(). But how can i add the instance to a list so that each instance when called should call its methods?
CONTROL
namespace create_interface
{
interface Control
{
void SetTime(params object[] paramsArr);
void Nop(params object[] paramsArr);
}
public class CM
{
Control c = new ControlImpl();
public List<object> ControlMain()
{
List<object> methods = new List<object>();
methods.Add(new Action<object[]>(c.SetTime));
methods.Add(new Action<object[]>(c.Nop));
return methods;
}
}
}
ControlImpl :
namespace create_interface
{
public class ControlImpl : Control
{
void Control.SetTime(params object[] paramsArr)
{
Console.WriteLine("inside Control.SetTime {0} ", paramsArr[0]);
}
void Control.Nop(params object[] paramsArr)
{
Console.WriteLine("inside Control.Nop ");
}
}
}
Runtime:
namespace create_interface
{
public class runtime
{
public void call(params object[] methodparams)
{
if ((methodparams[0].Equals(0)) || (methodparams[0].Equals(1)))
{
//List<Control> objectlists = cmObject.ControlObjectList();
List<object> methods = cmObject.ControlMain();
//Console.WriteLine(methods.Count);
Action<object[]> method = (Action<object[]>)methods[(int)methodparams[0]]; //object[]
object[] args = new object[] { methodparams[1] };
method(args);
}
else
Console.WriteLine("wrong ID number entered");
}
Test_main:
namespace create_interface
{
class test_main
{
static void Main(string[] args)
{
long time;
CallingFunc CF = new CallingFunc();
Console.WriteLine("enter method ID");
int methodID = Convert.ToInt32(Console.ReadLine());
try
{
switch (methodID)
{
case 0:
Console.WriteLine("enter the time in long");
time = Convert.ToInt64(Console.ReadLine());
CF.call(methodID, time);
break;
case 1:
CF.call(methodID, null);
break;
default:
Console.WriteLine("you entered wrong method ID or parameters");
break;
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}

Please take a look at the following solution and we can use it as a base to come up with your final solution:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
namespace StackOverflow38200633
{
class Program
{
static void Main(string[] args)
{
Collection<IControl> controls = new Collection<IControl>();
controls.Add(ControlFactory.Create());
controls.Add(ControlFactory.Create());
controls.Add(ControlFactory.Create());
ControlManager manager = new ControlManager(controls);
Console.WriteLine("Enter method ID:");
int methodID = Convert.ToInt32(Console.ReadLine());
try
{
switch(methodID)
{
case 0:
Console.WriteLine("Enter the time in long: ");
long time = Convert.ToInt64(Console.ReadLine());
manager.InvokeAllSetTime(time);
break;
case 1:
manager.InvokeAllNop();
break;
default:
Console.WriteLine("You entered wrong method ID or parameters");
break;
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
}
public interface IControl
{
void SetTime(long time);
void Nop();
}
public class ConcreteControl : IControl
{
public void SetTime(long time)
{
Console.WriteLine("inside Control.SetTime {0} ", time);
}
public void Nop()
{
Console.WriteLine("inside Control.Nop ");
}
}
public class ControlManager
{
public void InvokeAllSetTime(long time)
{
foreach(IControl control in _controls) control.SetTime(time);
}
public void InvokeAllNop()
{
foreach(IControl control in _controls) control.Nop();
}
public ControlManager(Collection<IControl> controls)
{
_controls = controls;
}
public Collection<IControl> _controls { get; private set; }
}
public static class ControlFactory
{
public static IControl Create()
{
return new ConcreteControl();
}
}
}

Related

How to determine the original name of a function passed as a delegate

I want to make a scheduler that runs every 5 minutes, and keeps track of functions that need only be executed once a day. I want to store the last runtime of each job in a (static) dictionary 'LastRuntimePerJob'.
I have created a delegate and a function that only executes the job when it has not been run today.
The code below does not work since nameof(jobToPerform) returns jobToPerform.
How can I get the actual name of the function (Job1) from the delegate jobToPerform?
using System;
using System.Collections.Generic;
namespace Euler.Business.Problem.Progress
{
public class Scheduler
{
public delegate void JobToPerform();
public void Job1()
{
// Perform some task
}
public static Dictionary<string, DateTime> LastRuntimePerJob { get; set; } = new Dictionary<string, DateTime>();
public void RunScheduler()
{
ExecuteWhenNecessary(Job1);
}
public void ExecuteWhenNecessary(JobToPerform jobToPerform)
{
var nameOfCurrentJob = nameof(jobToPerform);
if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
|| LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
{
jobToPerform();
if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
{
LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
}
else
{
LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
}
}
}
}
}
nameof is used to get the literal name of variables, type or member and it is executed at compile time (no effect at runtime).
I think that you should use jobToPerform.Method.Name to retreive the delegate real method name, so check and try the following code and let me know!
using System;
using System.Collections.Generic;
namespace Euler.Business.Problem.Progress
{
public class Scheduler
{
public delegate void JobToPerform();
public void Job1()
{
// Perform some task
}
public static Dictionary<string, DateTime> LastRuntimePerJob { get; set; } = new Dictionary<string, DateTime>();
public void RunScheduler()
{
ExecuteWhenNecessary(Job1);
}
public void ExecuteWhenNecessary(JobToPerform jobToPerform)
{
//var nameOfCurrentJob = nameof(jobToPerform);
var nameOfCurrentJob = jobToPerform.Method.Name; //Returns delegate method name
if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
|| LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
{
jobToPerform();
if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
{
LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
}
else
{
LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
}
}
}
}
}
EDIT - Note: if the delegate is anonymous you retreive the runtime assigned name:
public void RunScheduler()
{
ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); });
}
the method name will be like: <RunScheduler>b__6_0.
You can modify the ExecuteWhenNecessary method signature to specify the method name you want to use as Dictionary Key:
public void ExecuteWhenNecessary(JobToPerform jobToPerform, , string nameOfCurrentJob = null)
{
if (string.IsNullOrWhiteSpace(nameOfCurrentJob))
{
nameOfCurrentJob = jobToPerform.Method.Name;
}
if (!LastRuntimePerJob.ContainsKey(nameOfCurrentJob)
|| LastRuntimePerJob[nameOfCurrentJob] < DateTime.Today)
{
jobToPerform();
if (LastRuntimePerJob.ContainsKey(nameOfCurrentJob))
{
LastRuntimePerJob[nameOfCurrentJob] = DateTime.Now;
}
else
{
LastRuntimePerJob.Add(nameOfCurrentJob, DateTime.Now);
}
}
}
And call method like:
ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); }, "MyMethodName"); //Anonymous
ExecuteWhenNecessary(() => { Console.WriteLine("Hello"); }, nameof(Job1));

How to pass parameters from main method to another class

How do I pass the parameters from main method to another class?
I have done like this. Is this right approach?
namespace classA
{
class Program
{
public static void Main(string[] args)
{
string abc= new string {"HELLO"};
Console.WriteLine("My result: {0}", ClassB(abc));
Console.Read();
}
public static string ClassB(string abc)
{
//code
return xyz;
}
}
}
well in the code you posted you have only one class with two methods but in principle yes, this would be one way:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string abc = "HELLO";
Console.WriteLine("My result: {0}", ClassB(abc));
Console.Read();
}
public static string ClassB(string abc)
{
return abc;
}
}
}
My result: HELLO
If you have your second method really in another STATIC class:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string abc = "HELLO";
Console.WriteLine("My result: {0}", myfuncclass.ClassB(abc));
Console.Read();
}
}
static class myfuncclass
{
public static string ClassB(string abc)
{
return abc;
}
}
}
My result: HELLO
And if your second method is NOT in a static class and your method is NOT static you have to create an instance of the class first and then call your method on this object:
namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
string abc = "HELLO";
myfuncclass test = new myfuncclass();
Console.WriteLine("My result: {0}", test.ClassB(abc));
Console.Read();
}
}
public class myfuncclass
{
public string ClassB(string abc)
{
return abc;
}
}
}

Ninject how to avoid array injection for multiple name bindings

Review the following code, where to take care of cases with both single and named binding for an interface, an abstract factory is used as suggested here
Parameterized Factories Using Ninject
Challenge here is, I need to introduce IEnumerable<T> bankingOperationList, instead of T bankingOperationList, since for named binding it will always use the abstract factory injection, Func<string,T> bankingOperationFunc, but if I don't use IEnumerable<T> suggested above it leads to exception, due to this for even non named single binding, I need to use something like:
bankingOperationList.FirstOrDefault().Withdraw(), even when I know there will only be one dependency.
Another challenge is, for some named bindings it has 30 - 40 bindings in few cases, which will be unnecessarily filled, when I can default T bankingOperationList to null, as it is not required. Please let me know, if the issue needs further clarification. Working Console project underneath.
public interface IBankingOperation
{
void Withdraw();
}
public class BankingOperationOne : IBankingOperation
{
public BankingOperationOne()
{
Console.WriteLine("Testing Constructor :: One :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation One");
}
}
public class BankingOperationTwo : IBankingOperation
{
public BankingOperationTwo()
{
Console.WriteLine("Testing Constructor :: Two :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation Two");
}
}
// Ninject Bindings
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<IBankingOperation>().To<BankingOperationOne>()
.Named("A");
Bind<IBankingOperation>().To<BankingOperationTwo>()
.Named("B");
Bind<Func<string,IBankingOperation>>().ToMethod(ctx => name => ctx.Kernel.Get<IBankingOperation>(name));
}
}
public class BankTran<T> where T : IBankingOperation
{
private IEnumerable<T> bankingOperationList = null;
private Func<string,T> bankingOperationFunc;
public BankTran(IEnumerable<T> boList = null,
Func<string,T> boFunc = null)
{
bankingOperationList = boList;
bankingOperationFunc = boFunc;
}
public void DoOperation(string identifier = null)
{
if(bankingOperationFunc != null)
bankingOperationFunc(identifier).Withdraw();
else
bankingOperationList.FirstOrDefault().Withdraw();
Console.WriteLine("Transaction Successful ");
}
}
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule)
var transaction = kernel.Get<BankTran<IBankingOperation>>();
transaction.DoOperation("A");
}
}
Edit 1, based on response by jbl
public interface IBankingOperation<T>
{
void Withdraw();
}
public class BankingOperationOne : IBankingOperation<TestOne>
{
public BankingOperationOne()
{
Console.WriteLine("Testing Constructor :: One :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation One");
}
}
public class BankingOperationTwo : IBankingOperation<TestTwo>
{
public BankingOperationTwo()
{
Console.WriteLine("Testing Constructor :: Two :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation Two");
}
}
public class TestOne { }
public class TestTwo { }
// Ninject Bindings
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("A");
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("B");
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<TestOne>));
Bind<Func<string, IBankingOperation<TestOne>>>().ToMethod(ctx => name => ctx.Kernel.Get<IBankingOperation<TestOne>>(name));
Bind<IBankingOperation<TestTwo>>().To<BankingOperationTwo>();
}
}
public class BankTran<T> where T : class
{
private IBankingOperation<T> bankingOperation;
private Func<string, IBankingOperation<T>> bankingOperationFunc;
public BankTran(IBankingOperation<T> bo = null,
Func<string, IBankingOperation<T>> boFunc = null)
{
bankingOperation = bo;
bankingOperationFunc = boFunc;
}
public void DoOperation(string identifier = null)
{
if (bankingOperationFunc != null && identifier != null)
bankingOperationFunc(identifier).Withdraw();
else if (bankingOperation != null)
bankingOperation.Withdraw();
Console.WriteLine("Transaction Successful ");
}
}
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new NinjectSettings { AllowNullInjection = true});
kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule)
var transaction = kernel.Get<BankTran<TestOne>>("A"); // Not Working
// var transaction = kernel.Get<BankTran<TestOne>>(); // Working
transaction.DoOperation();
}
}
Assuming BankingOperationOne is your default behaviour,
adding the following line in your Load method should allow to replace the IEnumerable<T> with T in your BankTran constructor :
Bind<IBankingOperation>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<>));
Another solution would be to just define a named binding for default behaviour
Bind<IBankingOperation>().To<BankingOperationOne>().Named("__DefaultBehaviour");
then
public void DoOperation(string identifier = "__DefaultBehaviour")
{
if (bankingOperationFunc != null)
bankingOperationFunc(identifier).Withdraw();
Console.WriteLine("Transaction Successful ");
}
Edit :
You should use the Ninject.Extenstions.Factory nuget package.
Using this package, the following code seems to fullfill you requirements.
public interface IBankingOperation<T>
{
void Withdraw();
}
public interface IBankingOperationFactory<T>
{
IBankingOperation<T> GetBankingOperation(string name);
}
public class BankingOperationOne : IBankingOperation<TestOne>
{
public BankingOperationOne()
{
Console.WriteLine("Testing Constructor :: One :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation One");
}
}
public class BankingOperationTwo : IBankingOperation<TestTwo>
{
public BankingOperationTwo()
{
Console.WriteLine("Testing Constructor :: Two :: Empty");
}
public void Withdraw()
{
Console.WriteLine("Money Withdrawl Operation Two");
}
}
public class TestOne { }
public class TestTwo { }
// Ninject Bindings
public class Bindings : NinjectModule
{
public override void Load()
{
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("A");
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().Named("B");
Bind<IBankingOperation<TestOne>>().To<BankingOperationOne>().WhenInjectedInto(typeof(BankTran<TestOne>));
Bind<IBankingOperationFactory<IBankingOperation<TestOne>>>().ToFactory();
Bind<IBankingOperation<TestTwo>>().To<BankingOperationTwo>();
}
}
public class BankTran<T> where T : class
{
private IBankingOperation<T> bankingOperation;
private IBankingOperationFactory<T> _bankingOperationFactory;
public BankTran(IBankingOperation<T> bo = null,
IBankingOperationFactory<T> bankingOperationFactory = null)
{
bankingOperation = bo;
_bankingOperationFactory = bankingOperationFactory;
}
public void DoOperation(string identifier = null)
{
if (_bankingOperationFactory != null && identifier != null)
_bankingOperationFactory.GetBankingOperation(identifier).Withdraw();
else if (bankingOperation != null)
bankingOperation.Withdraw();
Console.WriteLine("Transaction Successful ");
}
}
class Program
{
static void Main(string[] args)
{
var kernel = new StandardKernel(new NinjectSettings { AllowNullInjection = true });
kernel.Load(Assembly.GetExecutingAssembly()); // Load from Bindings (derived from NinjectModule)
var transaction = kernel.Get<BankTran<TestOne>>();
transaction.DoOperation();
transaction.DoOperation("A");
transaction.DoOperation("B");
}
}

storing a function template

I want to store some generic functions for later execution. The problem arises about the arguments of functions. For different types I want to create and store same generic function delegate, but I cannot do it. Below is my version of class to get functions;
public delegate void CGTaskHandler1<T>(T value) where T : IControllerBase;
public class CGTask
{
private CGTaskHandler1<IControllerBase> Aksiyon;
private IControllerBase param;
public void RegisterCGTask(CGTaskHandler1<IControllerBase> aFunc, IControllerBase aParam)
{
Aksiyon = aFunc;
param = aParam;
}
public void ExecuteCGTask()
{
try
{
Aksiyon(param);
}
catch (Exception ex)
{
Logger.SetLog("action execution failed ", LogType.error, ex.Message)
}
}
}
by this class I used an interface to collect every different type of argument under same name, however compiler wants exact same type and interface type seems not helping.
private void LoadScene(cScene ascn)
{
ascn.LoadScene();
}
public CGTask GetTask(String btnName)
{
CGTask back = new CGTask();
CGTaskHandler1<IControllerBase> alomelo = LoadScene; // type mismatch
back.RegisterCGTask(alomelo, thisScene);
//CGTask2<cScene> back = new CGTask2<cScene>();
//CGTaskHandler1<cScene> alomelo = LoadScene;
//back.RegisterCGTask(alomelo, thisScene);
return back;
}
so I changed my cgtask class to a generic class, so, argument type would be definite since when class is instantiated.
public class CGTask2<T>
{
private CGTaskHandler1<T> Aksiyon;
private T param;
public void RegisterCGTask(CGTaskHandler1<T> aFunc, T aParam)
{
Aksiyon = aFunc;
param = aParam;
}
public void ExecuteCGTask()
{
try
{
Aksiyon(param);
}
catch (Exception ex)
{
Logger.SetLog("action execution failed ", LogType.error, ex.Message);
}
}
}
however same problem I confront when I want to collect them in a list.
List<CGTask2<IControllerBase>> gorevler = new List<CGTask2<IControllerBase>>();
gorevler.Add(new CGTask2<cScene>()); // type mismatch
I need a way to keep functions like objects. Every time I make use of a generic function delegate I need to specify the type, and types of generic functions are not convertible. Is there a way to do this, keeping references to functions and collecting these references as objects?
public interface IControllerBase
{
void GetTalker();
void InitiliazeTalker();
}
public class cControllerBase : IControllerBase
{
public cControllerBase Parent=null;
protected Talker tk;
protected void GetTalker()
{
tk = Talker.Instance; // not initialized yet
}
protected void InitiliazeTalker()
{
tk.InitializeReTalk();
}
}
public class cScene : cControllerBase, IControllerBase
{
public String ID;
public String ScenePath;
public String SceneName;
public int Slot;
public String DBParent;
public List<cAnimation> Animations;
public List<cExport> Exports;
public Boolean IsActive;
public cScene()
{
GetTalker();
Animations = new List<cAnimation>();
Exports = new List<cExport>();
// ID = Guid.NewGuid().ToString();
IsActive = false;
}
public Boolean ParseXml(String pXmlPath)
{
if (String.IsNullOrEmpty(pXmlPath)) return false;
XmlDocument xdoc = new XmlDocument();
XmlNodeList anims = null;
XmlNodeList exps = null;
try
{
xdoc.Load(pXmlPath);
anims = xdoc.SelectNodes("//scene_description/animations/animation");
exps = xdoc.SelectNodes("//scene_description/exports/export");
}
catch (Exception ex)
{
Logger.SetLog("xml parse error", LogType.error, ex.Message);
return false;
}
cAnimation tempanim;
cExport tempexport;
foreach (XmlNode x in anims)
{
tempanim = new cAnimation();
foreach (XmlAttribute y in x.Attributes)
{
switch (y.Name)
{
case "name":
{
tempanim.AnimationName = y.Value;
break;
}
case "duration":
{
tempanim.AnimationDuration = Globals.GetIntValue(y.Value);
break;
}
case "end_animation_time":
{
tempanim.AnimationEndTime = Globals.GetIntValue(y.Value);
break;
}
case "start_animation_time":
{
tempanim.AnimationStartTime = Globals.GetIntValue(y.Value);
break;
}
}
}
tempanim.Parent = this;
Animations.Add(tempanim);
}
foreach (XmlNode x in exps)
{
tempexport = new cExport();
foreach (XmlAttribute y in x.Attributes)
{
switch (y.Name)
{
case "name":
{
tempexport.ExportName = y.Value;
break;
}
case "type":
{
switch (y.Value)
{
case "String":
{
tempexport.ExportType = ExportDataType.tString;
break;
}
case "File":
{
tempexport.ExportType = ExportDataType.tFile;
break;
}
case "Float":
{
tempexport.ExportType = ExportDataType.tFloat;
break;
}
case "Int":
{
tempexport.ExportType = ExportDataType.tInt;
break;
}
case "Bool":
{
tempexport.ExportType = ExportDataType.tBool;
break;
}
}
break;
}
case "value":
{
tempexport.ExportValue = y.Value;
break;
}
}
}
tempexport.Parent = this;
Exports.Add(tempexport);
}
return true;
}
public void ActivateScene()
{
tk.ActivateScene(Slot, SceneName);
IsActive = true;
}
public void DeactivateScene()
{
// to do
// tk'dan aktif scene listesi yapıp kontrol edebiliyor musun?
tk.DeactivateScene(Slot);
IsActive = false;
}
public Boolean IsSceneLoaded()
{
Boolean back = false;
back = tk.IsSceneLoaded(SceneName);
return back;
}
public void LoadScene()
{
tk.LoadScene(SceneName);
}
public void UnloadScene()
{
tk.UnloadScene(SceneName);
}
public void SetSceneName(String strxmlPath)
{
ScenePath = strxmlPath;
SceneName = strxmlPath.Substring(0, strxmlPath.LastIndexOf('\\'));
SceneName = SceneName.Replace('\\', '/');
SceneName = SceneName.Substring(SceneName.IndexOf("Projects") + 9);
}
}
Well a CGTask2<cScene> is a completely different type to CGTask2<IControllerBase>, you can't equate the two. You would have to have a list of, for example, ITask and make CGTask2 implement that. For example:
public interface ITask {}
public class CGTask2<T> : ITask
{
//snip
}
And now you can do this:
List<ITask> gorevler = new List<ITask>();
gorevler.Add(new CGTask2<cScene>());

Accessing methods of a child object, through a Dictionary

New programmer, using C# and VB 2015, first time post so please be gentle!
Basically I am using Dictionary for the first time, and I am trying to access the method useMedPack() which inside my MedPack class, which is a child of Item, which is being created when adding it to my Dictionary. The problem is that it says:
****EDIT**** I feel like I should have added the Item class in first time round (now added to the bottom). Following some awesome suggestions, I casted using ((MedPack)inventory["MedPack"]).useMedPack(); and it now works as intended! Although some of the feedback has been great and I have learned a lot from everyones suggestions! :)
'Item' does not contain a definition for useMedPack();.
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Dictionary<String, Item> inventory = new Dictionary<String, Item>();
inventory.Add("MedPack", new MedPack("MedPack", 1));
MedPack.pickUpMedPack(inventory);
//THIS IS THE PROBLEM inventory["MedPack"].useMedPack();
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
namespace ConsoleApplication1
{
class MedPack : Item
{
private int healthReturn = 10;
public MedPack() : base()
{
}
public MedPack(String itemName, int itemQuantity) : base(itemName, itemQuantity)
{
}
public void useMedPack()
{
decreaseQuantity(1);
}
public static void pickUpMedPack(Dictionary<String, Item> inventory)
{
if (!inventory.ContainsKey("MedPack"))
{
inventory.Add("MedPack", new MedPack("MedPack", 1));
Console.WriteLine("You found a MedPack! It was added to the inventory");
}
else
{
inventory["MedPack"].increaseQuantity(1);
Console.WriteLine("You found ANOTHER MedPack! It was added to the inventory");
}
}
}
}
namespace ConsoleApplication1
{
class Item
{
private String itemName;
private int itemQuantity;
public Item(String itemName, int itemQuantity)
{
this.itemName = itemName;
this.itemQuantity = itemQuantity;
}
public Item()
{
}
public void increaseQuantity(int increaseQuantity)
{
this.itemQuantity += increaseQuantity;
}
public void decreaseQuantity(int increaseQuantity)
{
this.itemQuantity -= increaseQuantity;
}
public String getName()
{
return this.itemName;
}
public void setName(String name)
{
this.itemName = name;
}
public int getQuantity()
{
return this.itemQuantity;
}
public void setQuantity(int x)
{
this.itemQuantity = x;
}
}
}
Your dictionary stores objects of type Item. There's no guarantee that an arbitrary Item will be a MedPack therefore you can't directly call useMedPack on it.
If, in your case, you know that the item is a MedPack you can just cast it:
((MedPack)inventory["MedPack"]).useMedPack();
or in two lines:
MedPack mp = (MedPack)inventory["MedPack"];
mp.useMedPack();
If, at run time, the item is not a MedPack, you'll get an exception.
If you want a single method that can be applied to all item types ,then define it in Item and override it in the sub-classes as necessary:
in Item:
public virtual void UseItem()
{
// base implementtaion
}
in MedPack:
public override void UseItem()
{
// implementation specific to MedPack
}

Categories