Class not recognizing method in other class - c#

I'm a new C# programmer, and am wondering why I'm getting a object does not contain a definition of 'methodName' and no extension method 'methodName' accepting a first argument of type 'object' could be found error. I'm not sure why it seems the two classes aren't connected.
Here is the class with my method definitions:
namespace Simple_Restaurant_Simulation
{
class ChickenOrder
{
public int quantity;
public int GetQuantity(int ChickenQuantity)
{
this.quantity = ChickenQuantity;
return quantity;
}
public void CutUp()
{
return;
}
public void Cook()
{
return;
}
}
}
and the calling methods:
namespace Simple_Restaurant_Simulation
{
class Employees
{
public dynamic NewRequest(int Quantity, string MenuItem)
{
if (MenuItem == "Chicken")
{
return new ChickenOrder();
}
else
{
return new EggOrder();
}
}
public dynamic CopyRequest(dynamic MenuItem)
{
/*TODO:
if(existing order){
return existing order;
}
else { return "Whaddaya think I am, a miracle worker?"};
*/
return null;
}
public int Inspect(object Order)
{
int InspectResult = 0;
return InspectResult;
}
private string PrepareFood(object Order)
{
string PrepareResult = null;
try
{
if (Order is ChickenOrder)
{
for (int i=0; i < this.GetQuantity; i++)
{
Order.CutUp();
}
Order.Cook();
PrepareResult = "Chicken order has been cooked";
}
return PrepareResult;
}
catch (Exception)
{
}
}
}
}
Thanks for your help

I am not sure what you are trying to do here but the reason why the PrepareMethod doesn't compile is that it accepts an object and the object type obviously has no CutUp() method.
You could use the as operator to try to cast the Order object to a ChickenOrder:
ChickenOrder chickenOrder = Order as ChickenOrder;
if (chickenOrder != null)
{
for (int i = 0; i< this.GetQuantity; i++)
{
chickenOrder.CutUp();
}
chickenOrder.Cook();
PrepareResult = "Chicken order has been cooked";
}
Note that the cast will only succeed if the object that you are passing the PrepareFood method at runtime actually is a ChickenOrder. And for you to be able to pass a ChickenOrder object to a method that accepts an Order argument, the ChickenOrder class should inherit from Order:
class ChickenOrder : Order
{
...
}
Both EggOrder and ChickenOrder are specific types of orders that should inherit from the Order base class. This also means that you can change the return type of the NewRequest method from dynamic to Order and the type of the parameter that you are passing to the other methods from object to Order.

Related

How do I correctly instance a generic class from field type and put it in an array

I am trying to create an instance of the MonobehaviourField<T> class and put it in the monobehaviourFields array. I want to use the type from the current field from monobehaviourFields as T. This line
monobehaviourFields[i] = new MonobehaviourField<typeof(fieldType)>("test");
isn't working. How can I make an instance based on the fieldType and put it in the array?
using UnityEngine;
using System.Reflection;
using System;
using System.Linq;
[Serializable]
public class MonobehaviourWrapper
{
private MonobehaviourField<object>[] monobehaviourFields;
public MonobehaviourWrapper(FieldInfo[] fields)
{
monobehaviourFields = new MonobehaviourField<object>[fields.Length];
for (int i = 0; i < monobehaviourFields.Length; i++)
{
Type fieldType = fields[i].FieldType;
monobehaviourFields[i] = new MonobehaviourField<typeof(fieldType)>("test");
}
}
[Serializable]
public class MonobehaviourField<T>
{
[SerializeField] private string fieldName;
[SerializeField] private T objectContainer;
[SerializeField] private string typeName;
public MonobehaviourField(string fieldName)
{
this.fieldName = fieldName;
this.typeName = typeof(T).FullName;
}
public Type FieldType { get { return Type.GetType(typeName); } }
public T ObjectContainer { get { return objectContainer; } set { objectContainer = value; } }
public string FieldName { get { return fieldName; } set { fieldName = value; } }
}
}
This can be done, but you will need to change your code a bit.
You cannot have an MonobehaviourField<object>[] and add, say a MonobehaviourField<string> to the array: MonoBehaviourField is not covariant. I have declared a non-generic base class, MonobehaviourFieldBase to get around this. See, e.g. this question which had a similar issue.
You need to construct the generic class to make an instance of it, then use reflection to call the constructor. Here I use MakeGenericType to get from MonobehaviourField<> (note that there are no type parameters specified) to create a MonobehaviourField<T> where T is fieldType. I then use Type.GetConstructor to get the relevant constructor, and ConstructorInfo.Invoke to actually call the constructor. Note that Invoke returns an instance of type Object so it needs to be casted to the interface to be added to the array.
Here is the code (note that for brevity I've removed the parts of your code which aren't part of your problem):
public class MonobehaviourWrapper
{
private MonobehaviourFieldBase[] monobehaviourFields;
public MonobehaviourWrapper(FieldInfo[] fields)
{
monobehaviourFields = new MonobehaviourFieldBase[fields.Length];
for ( int i = 0; i < monobehaviourFields.Length; i++ )
{
Type fieldType = fields[i].FieldType;
var constructedGenericType = typeof(MonobehaviourField<>).MakeGenericType(fieldType);
var constructor = constructedGenericType.GetConstructor(new Type[] { typeof(string) });
object resultOfConstructor = constructor.Invoke(new object[] { "This code has worked" });
monobehaviourFields[i] = (MonobehaviourFieldBase)resultOfConstructor;
}
}
public IEnumerable<MonobehaviourFieldBase> MonobehaviourFields
{
get
{
return monobehaviourFields;
}
}
public class MonobehaviourField<T> : MonobehaviourFieldBase
{
public MonobehaviourField(string name)
{
FieldName = name;
}
}
}
and the base class:
public class MonobehaviourFieldBase
{
private string fieldName;
public string FieldName
{
get
{
return fieldName;
}
set
{
fieldName = value;
}
}
}
Here is a working example of the code above.

Cannot access public methods through dll

I've a function QMain() whose return type is object.
public class QMain
{
public object objQ(string str)
{
if (str.ToUpper() == "A")
{
clsA objA = new clsA();
return objA;
}
else if (str.ToUpper() == "B")
{
clsB objB = new clsB();
return objB;
}
else
return "";
}
}
Following is clsA:
public class clsA
{
public string strMessage { get; private set; }
public static string staticField;
public bool cantAccessThisFn(string str)
{...}
}
Both of the above classes are in same project which is a class library. I've created another console application wherein I've included the above project's dll. Now, I'm doing:
QMain obj=new QMain();
object A=obj.objQ("A");
I can get strMessage, staticField but not cantAccessThisFn. If I directly make an object of clsA, I'm able to get cantAccessThisFn. Is there any way to get access to this function from obj (object of class QMain)?
I get the following error:
'object' does not contain a definition for 'cantAccessThisFn' and no extension method 'cantAccessThisFn' accepting a first argument of
type 'object' could be found (are you missing a using directive or an
assembly reference?)
The problem is your objQ method returns an object. You haven't defined any (extension) methods on object, so cantAccessThisFn definitely can't be accessed.
What you should do is this: create an interface with all methods you want to share between the two classes, and don't return object, but return IYourInterfaceName. Then you can access those methods and properties defined on the interface.
Something like this:
public class clsA : IYourInterface
{
...
}
public interface IYourInterface
{
string strMessage { get; }
bool cantAccessThisFn(string str);
}
Then your method should look like:
public IYourInterface objQ(string str)
{ ... }
And your assignment like this:
IYourInterface a = obj.objQ("A");
Now it is valid to call:
a.cantAccessThisFn("z");
This is to help you understand! and not the recommended solution.
Marked Patricks answer up, as that is the more correct way...
but to achieve what you had you could do something like.
Also I applied the standard naming camel cases for the Classes, Properties and local variables.
This also allows for ClsA and ClsB to have completely different Method/Property names. Again I am not suggesting this as the way to do it but to rather help understand what its happening.
public class Program
{
static void Main()
{
QMain obj = new QMain();
object a = obj.objQ("A");
//FYI the below commended out is not possible...
//ClsA.staticField is but that is not the instance you created.
//------------
//a.staticField //<--- not possible
//------------
var someA = a as ClsA; //<--- attempts to cast it as ClsA
var someB = a as ClsB; //<--- attempts to cast it as ClsB
if (someA != null) //check if the cast was successful
{
var var1 = someA.StrMessage;
}
else if (someB != null)
{
//...
}
}
}
public class QMain
{
public object objQ(string str)
{
if (str.ToUpper() == "A")
{
ClsA objA = new ClsA();
return objA;
}
else if (str.ToUpper() == "B")
{
ClsB objB = new ClsB();
return objB;
}
else
return "";
}
}
public class ClsA
{
public string StrMessage { get; private set; }
public static string StaticField;
public bool CantAccessThisFn(string str)
{
return true;
}
}
public class ClsB
{
public string StrMessageMyC { get; private set; }
public static string StaticFieldMyC;
public bool CantAccessThisFnMyC(string str)
{
return true;
}
}

C# Tuple list inside class inside class not set to instance of object [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 8 years ago.
I'm trying to use a tuple list inside a custom class that wraps some methods from mutliple classes inside a game. I'm getting an 'object reference not set to instance of object error' just after the "ENTERED ADD METHOD A-1" is displayed in the cosole from the 1st Add method of the wrapper class. Clearly, Im not setting up the list correctly, but I can't see where the issue is. Any help would be appreciated as I'm new to working with 'classes'.
// wrappers & classes
KilledActorsWrapper KilledActors = new KilledActorsWrapper();
public class KilledActorsWrapper
#region KilledActorsWrapper class
{
public KilledActorsWrapper()
{ // constructor
if (Type.GetType("KilledActorsWrapper") == null) // check to see if class has been initiated
{ //class with the given name does not exist so instantiate it
List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>> m_KilledActors =
new List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>>();
m_KilledActors.Clear();
ConsoleWriteline("INITIALISED KILLEDACTORS LIST");
}
else
{ // class with the given name exists so show an error, cannot initate the class twice
ColoredConsoleWrite(ConsoleColor.DarkGreen, "INITIALISING KILLEDACTORS LIST FAILED");
throw new Exception("KilledActorsWrapper class already exists. Are you typing to initiate a second instance of this class?");
}
}
public void Add(AiActor killedActor, List<DamagerScore> damages)
{
ConsoleWriteline("ENTERED ADD METHOD A");
Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>> tuple = new Tuple<AiActor, AiDamageInitiator, NamedDamageTypes,
List<DamagerScore>>(killedActor, null, NamedDamageTypes.AirbrakeDriveFailure, damages);
ConsoleWriteline("ENTERED ADD METHOD A-1");
m_KilledActors.Add(tuple);
ConsoleWriteline("ENTERED ADD METHOD A-2");
}
public void Add(AiActor killedActor, AiDamageInitiator initiator, NamedDamageTypes damageType)
{
ConsoleWriteline("ENTERED ADD METHOD B");
Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>> tuple = new Tuple<AiActor, AiDamageInitiator, NamedDamageTypes,
List<DamagerScore>>(killedActor, initiator, damageType, null);
ConsoleWriteline("ENTERED ADD METHOD B-1");
this.m_KilledActors.Add(tuple);
ConsoleWriteline("ENTERED ADD METHOD B-2");
}
public int Count
{
get { return m_KilledActors.Count; }
}
public List<DamagerScore> GetDamagerScore(AiActor killedActor)
{
for (int i = 0; i < m_KilledActors.Count; i++)
{
if (m_KilledActors[i].Item1 == killedActor)
{
return (List<DamagerScore>)m_KilledActors[i].Item1;
}
}
return null;
}
public List<AiDamageInitiator> GetDamageInitiators(AiActor killedActor)
{
List<AiDamageInitiator> damageinitiators = null;
for (int i = 0; i < m_KilledActors.Count; i++)
{
if (m_KilledActors[i].Item1 == killedActor)
{
damageinitiators.Add((AiDamageInitiator)m_KilledActors[i].Item2);
}
}
return damageinitiators;
}
public List<NamedDamageTypes> GetNamedDamageTypes(AiActor actor)
{
List<NamedDamageTypes> nameddamagetypes = null;
for (int i = 0; i < m_KilledActors.Count; i++)
{
if (m_KilledActors[i].Item1 == actor)
{
nameddamagetypes.Add((NamedDamageTypes)m_KilledActors[i].Item3);
}
}
return nameddamagetypes;
}
public void Clear()
{
m_KilledActors.Clear();
}
private List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>> m_KilledActors { get; set; }
}
#endregion
public override void OnActorDead(int missionNumber, string shortName, AiActor actor, List<DamagerScore> damages)
#region process when an actor dies
{
base.OnActorDead(missionNumber, shortName, actor, damages);
KilledActors.Add(actor, damages); // call the wrapper class
}
public override void OnActorDamaged(int missionNumber, string shortName, AiActor actor, AiDamageInitiator initiator, NamedDamageTypes damageType)
{
base.OnActorDamaged(missionNumber, shortName, actor, initiator, damageType);
KilledActors.Add(actor, initiator, damageType); // call the wrapper class
}
Either m_KilledActors or tuple is not defined.
In this case the bug is in your constructor
List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>> m_KilledActors = new List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>>();
This causes a duplicate definition of m_KilledActors.. change it to just
m_KilledActors = new List<Tuple<AiActor, AiDamageInitiator, NamedDamageTypes, List<DamagerScore>>>();

After creating an instance how to cast it to the created type

say I have a method that returns a type:
private Type GetPersonOrOrganisation(someParameter)
{
either return Person type or Organisation type
}
Then I call this method:
Type type = GetPersonOrOrganisation(someParameter);
I then try to create a new instance of the returned type:
var newContact = Activator.CreateInstance(type);
What I'm left with is that newContact is of type object. What I wanted was newContact to be of either type Person or Organisation depending on what was returned from GetPersonOrOrganisation.
Does anyone know how to get the newContact cast to the correct type?
This definitely has some code smell to it. But there are perhaps some ways around it.
You might want to consider an interface that both person and organization implement if you are going to interact with them the same way. Or maybe a base class, depending on your specific scenario.
Beyond that, we probably need what you're trying to do afterwards to be able to give suggestions. Without the interface (or some other base class), you can't have ONE object that can be either of those types. The only thing they have in common currently is object.
You could do some different things like if (newContact is Person) { } else if (newContact is Organisation) { } or similar depending on your scenario, but that's really getting into the code smell unless you're absolutely stuck with those objects and methods the way they are.
You can return an initialized object from the function and test it using GetType() and typeof. Below is one example (certainly Tim's example will work as well).
public class Person
{
}
public class Organization
{
}
class Program
{
// Generate a Person if i == true or Organization if i == false
static object GetPersonOrOrganization(bool i)
{
if (i == true)
{
return new Person();
}
else
{
return new Organization();
}
}
static void Main(string[] args)
{
var p = GetPersonOrOrganization(true); // Generates a Person.
if (p.GetType() == typeof(Person))
{
Console.WriteLine("Person!"); // This prints.
}
else
{
Console.WriteLine("Organization");
}
var o = GetPersonOrOrganization(false); // Generates an Organization.
if (o.GetType() == typeof(Person))
{
Console.WriteLine("Person!");
}
else
{
Console.WriteLine("Organization!"); // This prints.
}
Console.ReadLine();
}
}
You need somethign like this:
public interface IPersonOrganization {
}
public class Peron : IPersonOrganization {
}
public class Organization : IPersonOrganization {
}
private IPersonOrganization GetPersonOrganization(bool isPerson) {
if (isPerson)
return new Person();
else
return new Organization;
}
Here's one way; though this assumes a parameterless constructor exists:
using System;
namespace StackOverflow.Demos
{
class Program
{
public static void Main(string[] args)
{
new Program();
Console.ReadKey();
}
private Program()
{
Type type = GetPersonOrOrganisation(new Person());
//object myInstance = GetInstanceOfType(type);
var myInstance = GetInstanceOfType(type);
Console.WriteLine(myInstance.ToString());
type = GetPersonOrOrganisation(new Organization());
myInstance = GetInstanceOfType(type);
Console.WriteLine(myInstance.ToString());
}
private Type GetPersonOrOrganisation(object what)
{
return what.GetType();
}
private object GetInstanceOfType(Type type)
{
//return type.GetConstructor(new Type[] { }).Invoke(new object[] { });
return Activator.CreateInstance(type);
}
}
public class Person
{
public Person() { }
}
public class Organization
{
public Organization() { }
}
}
Is this the issue you're having?
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType());
Console.WriteLine(Test(myInstance));
}
private string Test(object x) //this is the method being called
{
return string.Format("Object - {0}", x.ToString());
}
private string Test(Person x) //this is what you were hoping for
{
return string.Format("Person - {0}", x.ToString());
}
private string Test(Organization x)
{
return string.Format("Org - {0}", x.ToString());
}
One fix is this (not recommended):
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType());
Console.WriteLine(Test(myInstance));
}
private string Test(object x) //redirect the call to the right method
{
if (x is Person)
return Test(x as Person);
else
return Test(x as Organization);
}
private string Test(Person x) { return string.Format("Person - {0}", x.ToString()); } //this is what you were hoping for
private string Test(Organization x) { return string.Format("Org - {0}", x.ToString()); }
A better solution is this:
public interface ITestMethod { string Test();}
public class Person : ITestMethod
{
public Person() { }
public string Test() { return string.Format("Person - {0}", this.ToString()); }
}
public class Organization : ITestMethod
{
public Organization() { }
public string Test() { return string.Format("Org - {0}", this.ToString()); }
}
//...
public void Demo()
{
var myInstance = Activator.CreateInstance((new Person()).GetType()) as ITestMethod;
Console.WriteLine(myInstance.Test());
}
//...

Encapsulating Action<T> and Func<T>?

I'm trying to make a design for some sort of IExecutable interface. I will not get into details, but the point is that I have several Actions that need to be executed from a base class. They may take different parameters (no big deal), and they may/may not return a value.
So far, this is my design:
public abstract class ActionBase
{
// ... snip ...
}
public abstract class ActionWithResultBase<T>: ActionBase
{
public abstract T Execute();
}
public abstract class ActionWithoutResultBase: ActionBase
{
public abstract void Execute();
}
So far, each of my concrete actions need to be a child from either ActionWithResultBase or ActionWithoutResult base, but I really don't like that. If I could move the definition of Execute to ActionBase, considering that the concrete class may or may not return a value, I will have achieved my goal.
Someone told me this could be done with using Func and Action, for which I totally agree, but I can't find a way to have that into one single class so that the caller would know if the action is going to return a value or not.
Brief: I want to do something like:
// Action1.Execute() returns something.
var a = new Action1();
var result = a.Execute();
// Action2.Execute() returns nothing.
var b = new Action2();
b.Execute();
If you want a lightweight solution, then the easiest option would be to write two concrete classes. One will contain a property of type Action and the other a property of type Func<T>:
public class ActionWithResult<T> : ActionBase {
public Func<T> Action { get; set; }
}
public class ActionWithoutResult : ActionBase {
public Action Action { get; set; }
}
Then you can construct the two types like this:
var a1 = new ActionWithResult<int> {
CanExecute = true,
Action = () => {
Console.WriteLine("hello!");
return 10;
}
}
If you don't want to make Action property read/write, then you could pass the action delegate as an argument to the constructor and make the property readonly.
The fact that C# needs two different delegates to represent functions and actions is quite annoying. One workaround that people use is to define a type Unit that represents "no return value" and use it instead of void. Then your type would be just Func<T> and you could use Func<Unit> instead of Action. The Unit type could look like this:
public class Unit {
public static Unit Value { get { return null; } }
}
To create a Func<Unit> value, you'll write:
Func<Unit> f = () => { /* ... */ return Unit.Value; }
The following interfaces should do the trick -- it's essentially copying the Nullable pattern
public interface IActionBase
{
bool HasResult { get; }
void Execute() { }
object Result { get; }
}
public interface IActionBase<T> : IActionBase
{
new T Result { get; }
}
public sealed class ActionWithReturnValue<T> : IActionBase<T>
{
public ActionWithReturnValue(Func<T> action) { _action = action; }
private Func<T> _action;
public bool HasResult { get; private set; }
object IActionBase.Result { get { return this.Result; } }
public T Result { get; private set; }
public void Execute()
{
HasResult = false;
Result = default(T);
try
{
Result = _action();
HasResult = true;
}
catch
{
HasResult = false;
Result = default(T);
}
}
}
public sealed class ActionWithoutReturnValue : IActionBase
{
public bool HasResult { get { return false; } }
object IActionBase.Result { get { return null; } }
public void Execute() { //... }
}
You know that you can ignore the return value of a method right? You don't have to use it.
what about something simple:
public class ActionExecuter
{
private MulticastDelegate del;
public ActionExecuter(MulticastDelegate del)
{
this.del = del;
}
public object Execute(params object[] p)
{
return del.DynamicInvoke(p);
}
}

Categories

Resources