Get field values from class within class - c#

This has been driving me mad for a while now. I have a class which contains other classes. I need to loop through the first class looking for typeof second class then retreive the value of the fields.
the below code obviously fails on the line
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
as this isn't a valid field. Possibly I'm going about this the wrong way - any ideas?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication4
{
class Program
{
static void Main(string[] args)
{
MyFirstClass mFC = new MyFirstClass();
FieldInfo[] fI = mFC.GetType().GetFields();
foreach (FieldInfo field in fI)
{
if (field.FieldType.Name == "MySecondClass")
{
//get the fields
Console.WriteLine(field.GetValue(mFC.field.secondClassString));
}
}
}
}
class MyFirstClass
{
public MySecondClass firstMSC = new MySecondClass("First Instance");
public MySecondClass secondMSC = new MySecondClass("Second Instance");
public string firstClassString = "I'm from the first class";
public int firstClassInt = 5;
}
class MySecondClass
{
public MySecondClass(string input)
{
this.secondClassString = input;
}
public string secondClassString;
public int secondClassInt = 10;
}
}

field.GetValue accepts the instance from which it gets the field value.
In your case I would expect it should be field.GetValue(mFC).
Also field.FieldType.Name == "MySecondClass" is not the best way to check the type as type name change will cause code to break. I recommend replacing it with field.FieldType == typeof(MySecondClass).

((MySecondClass)field.GetValue(mFC)).secondClassString;
use this inside console.writeline

Related

Calling specific namespace and class using Strings

I am currently writing a program in C#, this program has a folder called Classes, many subfolders named a - f, and actual cs files within that folder named aa - cc.
a-f are namespaces
aa-cc are classes.
So if I wanted to invoke a method from Classes\b\bb.cs I'd have to type every time
b.bb,methodName();
It will also generate two Strings which will decide what we are going to be executing.
String myType = "b";
String myClass = "bb";
String toReturn = "";
There are many combinations of myType and myClass so I've had to write a lot of if loops
if (myType.equals("b") && myClass.equals("bb") return toReturn = b.bb.myMethod();
if (myType.equals("b") && myClass.equals("aa") return toReturn = b.aa.myMethod();
this is quite a lot of typing and I feel like there is an easier way to do this since I already know what know what namespace I want to access and what method I want to call.
Is there any way I could do something like
myType.myClass.myMethod()
where myType is the namespace, and myClass is the class I wish to call. This would avoid me typing out ever possible combination.
Improved sample with delegates. Homework: add hash to store delegates in GetDelegate method.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using TestConsole.Data;
namespace NamespaceA
{
public class ClassAB
{
public void MyMethod()
{
Console.WriteLine("You invoke NamespaceA.ClassAB.MyMethod");
}
public static void MyStaticMethod()
{
Console.WriteLine("You invoke NamespaceA.ClassAB.MyStaticMethod");
}
}
}
namespace TestConsole
{
public delegate void DoSomethingUseful(); // same as Action delegate
class Program
{
/// <summary>
/// create delegate
/// </summary>
/// <param name="namespace"> namespace name </param>
/// <param name="class"> class name </param>
/// <param name="method"> method name </param>
/// <returns></returns>
public static DoSomethingUseful GetDelegate(string #namespace, string #class, string method)
{
// common argument checks
if (#namespace == null) throw new ArgumentNullException("namespace");
if (#class == null) throw new ArgumentNullException("class");
if (method == null) throw new ArgumentNullException("method");
// find class
Type type = Type.GetType(#namespace + "." + #class);
if (type == null) throw new Exception("type not found");
// find method
MethodInfo methodInfo = type.GetMethod(method);
if (methodInfo == null) throw new Exception("method not found");
// create the delegate
return (DoSomethingUseful)Delegate.CreateDelegate(typeof(DoSomethingUseful), methodInfo.IsStatic ? null : Activator.CreateInstance(type), methodInfo);
}
static void Main(string[] args)
{
// creating delegates
DoSomethingUseful methodA = GetDelegate("NamespaceA", "ClassAB", "MyMethod");
DoSomethingUseful methodB = GetDelegate("NamespaceA", "ClassAB", "MyStaticMethod");
// usage
methodA();
methodB();
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
Complete code sample below.
Remember, that you should create class instance, if your class method is not static (object instance = Activator.CreateInstance(type););
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using TestConsole.Data;
namespace NamespaceA
{
public class ClassAB
{
public void MyMethod()
{
Console.WriteLine("You invoke NamespaceA.ClassAB.MyMethod");
}
public static void MyStaticMethod()
{
Console.WriteLine("You invoke NamespaceA.ClassAB.MyStaticMethod");
}
}
}
namespace TestConsole
{
class Program
{
static void Main(string[] args)
{
Type type = Type.GetType("NamespaceA.ClassAB");
object instance = Activator.CreateInstance(type);
type.GetMethod("MyMethod").Invoke(instance, null); // instance is required
type.GetMethod("MyStaticMethod").Invoke(null, null); // instance is not required
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}
use static.
public static HelperClass
{
public static void HelperMethod() {
// ...
}
}
Usage (after adding a reference to your Class Library).
HelperClass.HelperMethod();

Ninject factory not working with conventions for me

I am trying to use the method of binding located here but having no luck
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface
https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Keep in mind I am not trying to do it this way:https://gist.github.com/akimboyko/4593576
Rather I am trying to use the convention GetMercedes() to mean
I am basically trying to achieve this:https://gist.github.com/akimboyko/4593576 with conventions specified in the above examples.
using Ninject;
using Ninject.Extensions.Factory;
using Ninject.Modules;
using Ninject.Parameters;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Test.NinjectFactory
{
public class Program
{
public static void Main()
{
using (var kernel = new StandardKernel(new CarModule()))
{
var factory = kernel.Get<ICarFactory>();
var mercedes =factory.GetMercedes();
int i = 1;
}
}
public interface ICar
{
void Drive();
}
public class Mercedes : ICar
{
readonly ICarFactory carFactory;
public Mercedes(ICarFactory carFactory)
{
this.carFactory = carFactory;
}
public void Drive()
{
var Mercedes = this.carFactory.GetMercedes();
}
}
public interface ICarFactory
{
ICar GetMercedes();
}
public class CarModule : NinjectModule
{
public override void Load()
{
//https://github.com/ninject/ninject.extensions.factory/wiki/Factory-interface%3A-Referencing-Named-Bindings
Kernel.Bind<ICarFactory>().ToFactory();
Bind<ICar>().To<Mercedes>().NamedLikeFactoryMethod<ICarFactory>(x => x.GetMercedes());//doesnt work for me
}
}
}
}
I'm posting this as an answer because it is most likely the cause.
The factory extensions use prefixed Get methods as a standard. You'll run into issues by calling any of your factory methods with prefixed Get and using NamedLikeFactoryMethod. For example, GetFord, GetMercedes, GetNissan. You'll notice that, in the example at the link you provided, the function is called CreateMercedes.
Change your function name to CreateMercedes or anything that doesn't start with Get and it should be fine.
I found the anwswer here:
https://gist.github.com/akimboyko/5338320
It seems you need a function to take care of the binding
public class BaseTypeBindingGenerator<InterfaceType> : IBindingGenerator
{
public IEnumerable<IBindingWhenInNamedWithOrOnSyntax<object>> CreateBindings(Type type, IBindingRoot bindingRoot)
{
if (type != null && !type.IsAbstract && type.IsClass && typeof(InterfaceType).IsAssignableFrom(type))
{
string.Format("Binds '{0}' to '{1}' as '{2}", type, type.Name, typeof(InterfaceType)).Dump();
yield return bindingRoot.Bind(typeof(InterfaceType))
.To(type)
.Named(type.Name) as IBindingWhenInNamedWithOrOnSyntax<object>;
}
}
}

How do I extract the results of a multicast delegate at runtime?

Not sure if this is possible but im wondering how I catch the return of two methods that are assigned to the same delegate (multicast). I basically wondered if there is a way to catch each return value? Perhaps I have to iterate over it, not really sure..
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace MutiCastDelegate2
{
class Program
{
delegate string HelloWorldDelegate();
static void Main(string[] args)
{
HelloWorldDelegate myDel1 = ReturnHelloWorld;
HelloWorldDelegate myDel2 = ReturnHelloWorld2;
HelloWorldDelegate myMultiDelegate = myDel1 + myDel2;
Console.WriteLine(myMultiDelegate());
Console.ReadLine();
}
public static string ReturnHelloWorld()
{
return "Return Hello World";
}
public static string ReturnHelloWorld2()
{
return "Return Hello World 2";
}
}
}
You can use MulticastDelegate.GetInvocationList() to get access to each delegate in the list, then you just have to call each one and retrieve the results:
var delegates = myMultiDelegate.GetInvocationList();
foreach (var d in delegates)
{
string result = (string) d.DynamicInvoke();
}

XML Serialisation question

I'm trying to teach-myself how to serialize/deserialize to/from XML using the attribute-based serializer. I've put the below code together for testing purposes but it seems that I might have missed a point or two. Can anyone assist me and tell me what to do to have the whole damn thing work properly? The code below should compile and run just fine but will throw an exception - something is probably wrong with my attributes.
What did I miss?
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.IO;
namespace XMLSerialisation_test
{
class Program
{
static void Main(string[] args)
{
World my_world = new World(new Point(20, 30));
for (int i = 0; i < 10; i++)
{
string property = String.Format("Property no.{0}", i);
my_world.PushWorldObject(new MyObject(new Point(i, i), property));
}
DataContractSerializer world_serializer = new DataContractSerializer(typeof(World));
try
{
using (Stream s = File.Create("output.xml"))
world_serializer.WriteObject(s, my_world);
}
catch (Exception e)
{
Console.WriteLine("Exception occured : {0}", e.Message);
}
}
}
}
WorldObject.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
namespace XMLSerialisation_test
{
[DataContract]
public struct Point // couldn't find the pre-defined Point for some reason
{
public Point(double x, double y)
{ X = x; Y = y; }
[DataMember]
public double X;
[DataMember]
public double Y;
}
[DataContract]
public abstract class WorldObject
{
public WorldObject() : this(0.0, 0.0)
{}
public WorldObject(Point loc)
{ m_location = loc; }
public WorldObject(double x, double y)
{
m_location.X = x;
m_location.Y = y;
}
[DataMember]
public Point Location
{
get { return m_location; }
set { m_location = value; }
}
protected Point m_location;
}
[DataContract]
public class MyObject : WorldObject
{
public MyObject(string prop)
: base(0.0, 0.0)
{ m_property = prop; }
public MyObject(Point p, string prop)
: base(p)
{ m_property = prop; }
[DataMember]
public string Property
{
get{ return m_property; }
set{ m_property = value; }
}
private string m_property;
}
}
World.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.Serialization;
using System.Xml.Serialization;
namespace XMLSerialisation_test
{
[DataContract]
class World
{
public World() : this(new Point(10, 10))
{ }
public World(Point size)
{ m_world_size = size; }
public bool PushWorldObject(WorldObject o)
{
try
{
WorldObjects.Add(o);
return true;
}
catch(Exception e)
{
Console.WriteLine("Exception occured : {0}", e.Message);
return false; }
}
#region Accessors
[DataMember]
public List<WorldObject> WorldObjects
{
get { return m_world_objects; }
set { m_world_objects = value; }
}
[DataMember]
public Point WorldSize
{
get { return m_world_size; }
private set { m_world_size = value; }
}
#endregion
#region Fields
private List<WorldObject> m_world_objects = new List<WorldObject>();
private Point m_world_size;
#endregion
}
}
Try this:
DataContractSerializer world_serializer = new DataContractSerializer(typeof(World), new List<Type> { typeof(MyObject) });
The problem is that PushWorldObject takes type WorldObject, but you are actually passing type MyObject. The serializer knows nothing about this type, so throws an exception. WorldObject is used within the World class, so this type is by known by default. However, MyObject is not used inside World - so you manually have to declare it as Known.
As an alternative, you can add the KnownType attribute like so:
[DataContract, KnownType(typeof(MyObject))]
class World
{
The biggest problem I see is the abstract WorldObject. You'll need to use a KnownType attribute there (or via config or method name- check MSDN for "Data Contract Known Types") to tell it about the known subtypes it might encounter (eg, MyObject).
Just to clarify: if you are serializing to xml for the purposes of having xml in a known format, then DataContractSerializer is a bad choice; you would do better to use XmlSerializer, which has more control over xml layout. You would use the [XmlElement] / [XmlAttribute] / [XmlType] / [XmlRoot] attributes instead of [DataMember] etc.
If you just want to use xml because it is text and stores the object, then DataContractSerializer is fine; and has other advantages, for example - not demanding a public parameterless constructor (which XmlSerializer does), and working with private members (which XmlSerializer doesn't).

Why my C# reflection code crashes?

I'm just trying reflection :
using System;
using System.Collections.Generic;
using System.Reflection;
public class CTest {
public string test;
}
public class MyClass
{
public static void Main()
{
CTest cTest = new CTest();
Type t=cTest.GetType();
PropertyInfo p = t.GetProperty("test");
cTest.test = "hello";
//instruction below makes crash
string test = (string)p.GetValue(cTest,null);
Console.WriteLine(cTest.GetType().FullName);
Console.ReadLine();
}
}
"test" is not a property, it's a field. You should use Type.GetField method to get a FieldInfo:
CTest CTest = new CTest();
Type t = CTest.GetType();
FieldInfo p = t.GetField("test");
CTest.test = "hello";
string test = (string)p.GetValue(CTest);
Console.WriteLine(CTest.GetType().FullName);
Console.ReadLine();
Others have observed that the member is a field. IMO, though, the best fix is to make it a property. Unless you're doing some very specific things, touching fields (from outside the class) is usually a bad idea:
public class CTest {
public string test { get; set; }
}
test is not a property, it is a member variable.
using System;
using System.Collections.Generic;
using System.Reflection;
public class CTest {
public string test;
public string test2 {get; set;}
}
public class MyClass
{
public static void Main()
{
CTest CTest = new CTest();
Type t=CTest.GetType();
FieldInfo fieldTest = t.GetField("test");
CTest.test = "hello";
string test = (string)fieldTest.GetValue(CTest);
Console.WriteLine(test);
PropertyInfo p = t.GetProperty("test2");
CTest.test2 = "hello2";
//instruction below makes crash
string test2 = (string)p.GetValue(CTest,null);
Console.WriteLine(test2);
Console.ReadLine();
}
}

Categories

Resources