Get Object from its name - c#

I have an object:
MyObject obj = new MyObject();
obj.X = "Hello";
obj.Y = "World";
Someone passes me a string:
string myString = "obj.X";
I want to get the value referenced to myString, like this:
var result = <Some Magic Expression>(myString); // "Hello"
Is it possible through reflection?

You can't exactly replicate this behaviour, because names of local variables aren't saved in the method's metadata. However, if you keep a dictionary of objects, you can address the object by its key:
public static object GetProperty(IDictionary<string, object> dict, string path)
{
string[] split = path.Split('.');
object obj = dict[split[0]];
var type = obj.GetType();
return type.InvokeMember(split[1], BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetField | BindingFlags.GetProperty, null, obj, null);
}
 
var dict = new Dictionary<string, object>();
var cl = new MyClass();
dict["obj"] = cl;
cl.X = "1";
cl.Y = "2";
Console.WriteLine(GetProperty(dict, "obj.X"));
Console.WriteLine(GetProperty(dict, "obj.Y"));
This can handle accessing fields and properties in the format "name.property". Doesn't work for dynamic objects.

Related

Create Class Dynamically During Runtime

Hi im trying to create a class dending on data gathered from a user input. Once its chosen id like to the create the field names and the data types based on that and fill that class with data from document effectively creating a list of that Class.
Eg I create a class called Class1 and give it 3 Properties : ID , Name , Weight and define there types as int , string , int
Then I want to fill it with data Eg : (Example in json to show structure)
ID:{
1,
2,
3
},
Name:{
A,
B,
c
},
Weight:{
10,
20,
30
}
Ive looked into Reflection and codeDom which both enable for me to make the Class but i cannot work out how to write to that new classes properties.
Code for codeDom Version:
string className = "BlogPost";
var props = new Dictionary<string, Type>() {
{ "Title", typeof(string) },
{ "Text", typeof(string) },
{ "Tags", typeof(string[]) }
};
createType(className, props);
I Create The Properties and their Types
static void createType(string name, IDictionary<string, Type> props)
{
var csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, "Test.Dynamic.dll", false);
parameters.GenerateExecutable = false;
var compileUnit = new CodeCompileUnit();
var ns = new CodeNamespace("Test.Dynamic");
compileUnit.Namespaces.Add(ns);
ns.Imports.Add(new CodeNamespaceImport("System"));
var classType = new CodeTypeDeclaration(name);
classType.Attributes = MemberAttributes.Public;
ns.Types.Add(classType);
foreach (var prop in props)
{
var fieldName = "_" + prop.Key;
var field = new CodeMemberField(prop.Value, fieldName);
classType.Members.Add(field);
var property = new CodeMemberProperty();
property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
property.Type = new CodeTypeReference(prop.Value);
property.Name = prop.Key;
property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName)));
property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), fieldName), new CodePropertySetValueReferenceExpression()));
classType.Members.Add(property);
}
var results = csc.CompileAssemblyFromDom(parameters, compileUnit);
results.Errors.Cast<CompilerError>().ToList().ForEach(error => Console.WriteLine(error.ErrorText));
}
This is just code i found elsewhere but if this where the code i wanted id do something like
var a = new List<BlogPost>()
and then
a."Property1" = "Title 1"
Hope this is informative
You could use reflection.
Main method to create desired object and populate its properties:
public object GenerateObject(string fullyQualifiedClassName,
Dictionary<string, object> nameToValueMap)
{
var actualObject = GetInstance(fullyQualifiedClassName);
if (actualObject == null)
return actualObject;
foreach (var prop in nameToValueMap)
{
SetPropValue(actualObject, prop.Key, prop.Value);
}
return actualObject;
}
Method to create instance of the desired class, based on fully qualified class name:
public object GetInstance(string fullyQualifiedName)
{
Type type = Type.GetType(fullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
foreach (var asm in AppDomain.CurrentDomain.GetAssemblies())
{
type = asm.GetType(fullyQualifiedName);
if (type != null)
return Activator.CreateInstance(type);
}
return null;
}
And last but not least, method to set property's value:
public bool SetPropValue<T>(T obj, string propName, object val)
{
if (string.IsNullOrEmpty(propName)) return false;
var prop = obj?.GetType()
.GetProperties()?
.FirstOrDefault(m => m.Name == propName);
if (prop != null)
{
prop.SetValue(obj, val);
return true;
}
return false;
}
Why not use dynamic object using expandoObject?
something like:
dynamic blogPost = new System.Dynamic.ExpandoObject();
blogPost.Tile = "Mary Water";
blogPost.Text= "your text here";

C# Equilavent of "dynamic" JavaScript object?

I want to create a single object (possibly Dictionary) with string keys that will have different variable types as the value (string, int, bool, Dictionary<string,string> etc). Is this possible?
*I understand this might just be a fundamental difference of two languages AKA square peg round hole
You can use dynamic as values type, that match better than object to the question and you need no future castings:
var dictionary = new Dictionary<string, dynamic>();
dictionary.Add("1", 10);
dictionary.Add("2", "test");
dictionary.Add("3", true);
foreach ( var item in dictionary )
Console.WriteLine($"{item.Key} is type: {item.Value.GetType().Name} = {item.Value}");
Console.WriteLine();
int v = dictionary["1"] + 10;
Console.WriteLine(v);
string s = dictionary["2"] + " one";
Console.WriteLine(s);
bool b = !dictionary["3"];
Console.WriteLine(b);
Output
1 is type: Int32 = 10
2 is type: String = test
3 is type: Boolean = True
20
test one
False
https://learn.microsoft.com/dotnet/csharp/programming-guide/types/using-type-dynamic
A Dictionary<string, object> is roughly equivalent to an object in JavaScript.
Example:
var dictionary = new Dictionary<string, object>
{
"myString" = "helloWorld",
"myChild" = new Dictionary<string, object>
{
"myName" = "bobby tables"
}
};
var myString = (string)dictionary["myString"];
var myName = (string)((Dictionary<string, object>)dictionary["myChild"])["myName"];
You can also use the dynamic keyword and ExpandoObject.
dynamic obj = new ExpandoObject();
obj.MyString = "helloWorld";
obj.MyChild = new ExpandoObject();
obj.MyChild.MyName = "bobby tables";
string myString = obj.MyString;
string myName = obj.MyChild.MyName;

Convert values based on parameter type using reflection

I have a array of objects and i want to convert these object in to its actual type based on the parameter type of a method using reflection .
The dictionary will change based on the json string.So I want to make the array of objects to proper type to pass the invoke method.
Here is my code .
class Program
{
static void Main(string[] args)
{
try
string json =#"{""Id"":21}";
Dictionary<string, object> paramList = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
Assembly asm = Assembly.GetExecutingAssembly();
Type jobType = (from t in asm.GetTypes()
where t.IsClass && t.FullName == "pathTest.Order"
select t).FirstOrDefault();
MethodInfo infoMethod = jobType.GetMethod("GetOrder");
object jobClassObject = asm.CreateInstance(jobType.FullName);
ParameterInfo[] parameters = infoMethod.GetParameters();
int count = parameters.Count();
Object[] pArray = { };
if (count > 0)
{
pArray = new object[count];
foreach (var methodArg in parameters)
{
var item = paramList.Where(m => m.Key == methodArg.Name).FirstOrDefault();
pArray[methodArg.Position] = Int32.Parse(item.Value.ToString());//hard coded
//Here I want to cast the value based on parameter type .
//parameter type(item.Value.ToString())
}
}
jobType.InvokeMember("GetOrder", BindingFlags.InvokeMethod | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, jobClassObject, pArray);
}
catch (Exception e)
{
}
Console.ReadLine();
}
}
The actual type of the parameter is stored in methodArg.ParameterType. You can use Convert.ChangeType to change the type of the object you get from your json string:
Type paramType = methodArg.ParameterType;
pArray[methodArg.Position] = Convert.ChangeType(item.Value, paramType);

Dynamic object property name begins with number

I have a dynamic object whose property begins with number. How to access this property?
For inst:
myResult.123; // this is unvalid
Any helps would be very appreciated.
If you are using ExpandoObject for your dynamic object, you can cast to IDictionary<string, object> and use an indexer;
dynamic expando = new ExpandoObject();
var dict = (IDictonary<string, object>)expando;
dict["123"] = 2;
Many other dynamic object implementations (e. g. JObject in Json.NET) provide similar functionality.
Here's an example with JObject:
var json = JsonConvert.SerializeObject(new Dictionary<string, object> { { "123", 10 } });
var deserialized = JsonConvert.DeserializeObject<object>(json);
// using the IDictionary interface
var ten = ((IDictionary<string, JToken>)deserialized)["123"].Value<JValue>().Value;
Console.WriteLine(ten.GetType() + " " + ten); // System.Int64 10
// using dynamic
dynamic d = deserialized;
Console.WriteLine(d["123"].Value.GetType() + " " + d["123"].Value); // System.Int64 10
Modified
Type t = myResult.GetType();
PropertyInfo[] props = t.GetProperties();
Dictionary<string, object> dict = new Dictionary<string, object>();
foreach (PropertyInfo prp in props)
{
object value = GetPropValue(myResult, prp.Name);
dict.Add(prp.Name, value);
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}

C# access object properties at runtime

I'm calling a web service that is returning this object. I know I should be using object reflection in C# to access the property of sentBatchTotal. However, I can't for the life of me figure out how to get to this property. I have looked at several other articles here and on MSDN but it's just not sinking in.
Here is my code, what am I doing wrong?
private void button1_Click(object sender, EventArgs e)
{
prdChal.finfunctions service = new prdChal.finfunctions();
//Type thisObject = typeof()
//Type myType = myObject.GetType();
//IList<PropertyInfo> props = new List<PropertyInfo>(myType.GetProperties());
String ThisName = "";
Object StatusReturn = new Object();
StatusReturn = service.UpdateGrantBillStatus(fundBox.Text, toBox.Text, fromBox.Text);
var type = StatusReturn.GetType();
var propertyName = type.Name;
//var propertyValue = propertyName.GetValue(myObject, null);error here
}
The following code uses reflection.
StatusReturn = service.UpdateGrantBillStatus(fundBox.Text, toBox.Text, fromBox.Text);
var type = StatusReturn.GetType();
var pi = type.GetProperty("sentBatchTotal");
if (pi != null) {
var propertyValue = pi.GetValue(StatusReturn, null);
}
But can't you just the webservice-method return-type instead of object? Than you can just read the property directly.
Something like:
WhatEverTypeYourServiceReturns StatusReturn = service.UpdateGrantBillStatus(fundBox.Text, toBox.Text, fromBox.Text);
string sentBatchTotal = StatusReturn.sentBatchTotal;
Don't declare your StatusReturn variable as an object type first.
//Object StatusReturn = new Object();
var StatusReturn = service.UpdateGrantBillStatus(fundBox.Text, toBox.Text, fromBox.Text);
if (StatusReturn.Count() > 0)
{
var fixedAsset = StatusReturn[0];
}
dynamic d = service.UpdateGrantBillStatus(fundBox.Text, toBox.Text, fromBox.Text);
string result = (string)d[0].sentBatchTotal;

Categories