here a solution is given to get value of a property of a class by supplying its name . now I wonder how I can do the same in this condition :
I have a class MyClass . this class ha a property of type Foo named foo . the Foo has a property of type Bar named bar . and bar has a string property named value .
properties are not static .
I want to be able to get value of foo.bar.value by passing the string "foo.bar.value" as propertyName . in other word I want to pass the property path to get its value .
is it possible ?
You can do this with a recursive method. Each call takes the value with the first word in path and call the method again with the rest of the part.
public object GetPropertyValue(object o, string path)
{
var propertyNames = path.Split('.');
var value = o.GetType().GetProperty(propertyNames[0]).GetValue(o, null);
if (propertyNames.Length == 1 || value == null)
return value;
else
{
return GetPropertyValue(value, path.Replace(propertyNames[0] + ".", ""));
}
}
This assumes that the properties are named like the classes. i.e. that the property of Type Foo is also named Foo. Without this assumption, the question is lacking some crucial information.
You can use the string.Split method to separate the string foo.bar.value at the dots. You will then have an array with one element per property name.
Iterate over that array and use PropertyInfo.GetValue to retrieve the value of the properties. The value returned in one operation is the instance passed to GetValue in the following iteration.
string props = "foo.bar.value";
object currentObject = // your MyClass instance
string[] propertyChain = props.Split('.');
foreach (string propertyName in propertyChain) {
if (propertyName == "") {
break;
}
PropertyInfo prop = currentObject.GetType().GetProperty(propertyName);
currentObject = prop.GetValue(currentObject);
if (currentObject == null) {
// somehow handle the situation that one of the properties is null
}
}
Update: I have added a safeguard to ensure this will work even if props is empty. In that case, currentObject will remain a reference to the original MyClass instance.
Assuming FOO is static, you can get the class from a string like this:
C# Reflection: How to get class reference from string?
...and then use the rest of the post you've linked to to get the property and value from there:
Get property Value by its stringy name
If FOO isn't static, you'll need to use reflection on the instance (which would negate the requirement to pass in the name of the class as a string, since you can get the class from the instance with GetType()) - remembering that Bar won't have a value in the class unless it is static.
As You pointing to answer of the question here , You need to make use of Reglection to achieve same thing.
With help of reflection you can read value of property.
something like this,
// dynamically load assembly from file Test.dll
Assembly testAssembly = Assembly.LoadFile(#"c:\Test.dll");
// get type of class Calculator from just loaded assembly
Type calcType = testAssembly.GetType("Test.Calculator");
// create instance of class Calculator
object calcInstance = Activator.CreateInstance(calcType);
// get info about property: public double Number
PropertyInfo numberPropertyInfo = calcType.GetProperty("Number");
// get value of property: public double Number
double value = (double)numberPropertyInfo.GetValue(calcInstance, null);
you need a put the code in one function and than split string as per you requirement
public object getvalue(string propname)
{
//above code with return type object
}
String[] array = string.Split("foo.bar.value");
//call above method to get value of property..
Read for detail : http://www.csharp-examples.net/reflection-examples/
Related
Using Roslyn, I'm to get the constant value of the following string parameter in this method call:
inst.someMethod($"{Constants.SomeValue}");
static class Constants
{
public static readonly string SomeValue= "some value";
}
I got an instance of InterpolatedStringExpressionSyntax type for the $"{Constants.SomeValue}" parameter.
Next, I need to get its value (which is the "Some value" string), and I tried to call semanticModel.GetConstantValue(expr); but it returns null
How can I get that value?
1) SemanticModel.GetConstantValue works only for compile time constant members, so you cannot use it to get a value of readonly field.
2) If you want to get a value of readonly field you actually need to analyze field initializer and constructors in the common cases to determine where and how this field was created and so on.
But in you simple example above, when you have a static class and static readonly field with initializer you can make something looks ike this:
InterpolatedStringExpressionSyntax interpolatedExpression = // you received it before
// as you know that your member is the first contet of InterpolatedStringExpressionSyntax
var symbolInfo = semanticModel.GetSymbolInfo(((interpolatedExpression).Contents[0] as InterpolationSyntax).Expression);
if (!(symbolInfo.Symbol is null))
{
// assume that exists only a one declaration
var fieldDeclaration = symbolInfo.Symbol.DeclaringSyntaxReferences[0].GetSyntax() as VariableDeclaratorSyntax;
if (!(fieldDeclaration is null))
{
// retrieves text from `SomeValue = "some value"`
var text = (fieldDeclaration.Initializer.Value as LiteralExpressionSyntax)?.Token.Text;
}
}
When attempt to fill an array in C# with my custom type class, the array populates with the class's location in the namespace. However, I need the array to populate with the values I specified with that type.
I have tried defining my array using each of these implementations with the same results:
List<FieldName> fieldNames = new List<FieldName>() { "event_ref", "user_id", "sys_time" };
FieldName[] fieldNames = { "event_ref", "user_id", "sys_time" };
In both cases the values that get implemented in the lower function calls (nothing fancy) is ElectronicSJP.DatabaseIF.FieldName for all three of the fields.
Upon setting a breakpoint, I can see that fieldNames is populated as so:
The values that I specified are at the next level down, if that table is expanded. My class for FieldName is defined as such:
class FieldName
{
private string name = "";
public static implicit operator string(FieldName fn)
{
return (fn == null) ? null : fn.name;
}
public static implicit operator FieldName(string fn)
{
return new FieldName { name = fn };
}
}
I suspect that I may need to add another implicit operator, or two, so I could use some help with that or any other ideas you think could fix this problem. Thanks.
When the debugger shows an object, or list of objects, it will show the type rather than a particular field.
In order to see a "user friendly value", one can either override the toString method that exists on the Object class, or you can decorate the property you want shown with the DebuggerDisplay Attribute (credit to Adam V up above in the comments!)
example:
public override string ToString()
{
return name;
}
Link to how to override a method. https://msdn.microsoft.com/en-us/library/ms173154.aspx
I have to following in vb.net and am having a rough time converting to c#. The fieldlist is a class that has several properties however only 2 are relevant for the below procedure. The code to call the procedure looks like myClass.Fields("Test") = 123456. The converters all drop the fieldname from the property. If I add it back then I get The name 'value' does not exist in the current context.
VB.net - works fine in VB
Public WriteOnly Property Fields(ByVal fieldName As String) As Object
Set(ByVal value As Object)
If mvarFieldData Is Nothing Then mvarFieldData = New FieldList
If mvarFieldData(fieldName) Is Nothing Then
mvarFieldData.Add(fieldName, value)
Else
mvarFieldData(fieldName).FieldValue = value
End If
End Set
End Property
c# - I'm doing something wrong here.
public object Fields(string fieldName)
{
set {
if (mvarFieldData == null)
{mvarFieldData = new FieldList();}
if (mvarFieldData[fieldName] == null)
{
mvarFieldData.Add(fieldName, value);
} else {
mvarFieldData[fieldName].FieldValue = value;
}
}
}
c# Converters(telerik) provide the below
public object Fields {
set {
if (mvarFieldData == null)
mvarFieldData = new FieldList();
if (mvarFieldData(fieldName) == null) {
mvarFieldData.Add(fieldName, value);
} else {
mvarFieldData(fieldName).FieldValue = value;
}
}
}
What is the scope of mVarFieldData, and what is it's exact type? It seems like it is a Collection of some sort.
The c# code above is not compilable as you are trying to mix a method syntax with a property syntax.
property:
public object Fields{ get; set{mvarFieldData = value;} }
Method:
public object Fields(string fieldname, object val){ mvarFieldData[fieldname] = val;}
By the looks of the decision making going on in the VB.Net property, I would think a public method may suit the situation better. I normally just use property's when a very minimum amount of validation is needed when setting a encapsulated type member.
Hope this helps.
You actually have a couple problems here.
Problem 1: Properties don't take arguments.
C# properties can't be passed an argument/parameter the way you're passing fieldname. There are a couple different ways you could solve this:
You can make an index property (used with myObject[fieldName] = blah rather than myObject.Fields[fieldName] = blah). Use the syntax public object this[string fieldName] to declare the property.
Since your property doesn't have a getter, you can just turn it into a single method with signature public void SetField(string fieldName, object value), called like so: myObject.SetField(fieldName, value).
You can expose mvarFieldData through a getter property: public Dictionary<?, ?> Fields { get { return mvarFieldData; } } which will let users access the dictionary (I assume that's what it is, based on usage) directly.
Problem 2: The key may not exist.
I'm not sure about dictionaries (or whatever similar structure mvarFieldData is) in VB.NET, but in C# there's a difference between a key whose value is null and a key that's not present in the structure.
var dict = new Dictionary<int, string>();
dict.Add(1, null);
if (dict[1] == null)
Console.WriteLine("This line will be displayed.");
if (dict[2] == null)
Console.WriteLine("The line above this one will throw an exception.");
In addition to your present code, you need a check for mvarFieldData.ContainsKey(fieldName) before you start checking the value associated with fieldName.
I have a set of user controls on a page that are dynamically loaded based on condition to run a variety reports (the condition driver). Each control has one or more properties exposed that will be used to get data from my database query. Because the controls vary for each report I wrote a procedure to access the appropriate control's property by name so I can send it to the database query in the code behind (C#). I got it all setup to access the public property like this:
stringVal = userControl.Attributes[stringName].ToString();
and it is telling me that I need to new up an object. I don't understand how I need to access that property dynamically by string name. In my immediate window I can see the property I want; but, it is not an "Attribute" as control.Attributes.Count = 0. So, how do I need to set this up properly so I can access it by string name? Do I need to decorate the property with something?
Thank you in advance.
Below, I've written a wrapper class you can use to set/get public fields or properties of the wrapped class by string name.
First, let's look at how you could use it on a class that had the public fields or properties StartDate and SocialSecurityNumber.
// First create the instance we'll want to play with
MyUserControl myControlInstance = new MyUsercontrol();
// MyUserContol has two properties we'll be using
// DateTime StartDate
// int SocialSecurityNumber
// Now we're creating a map to facilitate access to the properties
// of "myControlInstance" using strings
PropertyMap<MyUserControl> map =
new PropertyMap<MyUserControl>(myControlInstance);
// Since the map is directed toward "myControlInstance"
// this line is equivalent to:
// myControlInstance.StartDate = Datetime.Now;
map.Set<DateTime>("StartDate", DateTime.Now);
// This line is equivalent to:
// ssn = myUsercontrol.SocialSecurityNumber;
int ssn = map.Get<int>("SocialSecurityNumber");
And now on to how it's implemented:
public class PropertyMap<T>
{
readonly T Instance;
public PropertyMap(T instance)
{
Instance = instance;
}
public U Get<U>(string PropertyName)
{
// Search through the type's properties for one with this name
// Properties are things with get/set accessors
PropertyInfo property = typeof(T).GetProperty(PropertyName);
if (property == null)
{
// if we couldn't find a property, look for a field.
// Fields are just member variables, but you can only
// manipulate public ones like this.
FieldInfo field = typeof(T).GetField(PropertyName);
if (field == null)
throw new Exception("Couldn't find a property/field named " + PropertyName);
return (U)field.GetValue(Instance);
}
return (U)property.GetValue(Instance, null);
}
public void Set<U>(string PropertyName, U value)
{
// Search through the type's properties for one with this name
PropertyInfo property = typeof(T).GetProperty(PropertyName);
if (property == null)
{
// if we couldn't find a property, look for a field.
FieldInfo field = typeof(T).GetField(PropertyName);
if (field == null)
throw new Exception("Couldn't find a property/field named " + PropertyName);
field.SetValue(Instance, value);
return;
}
property.SetValue(Instance, value, null);
}
}
You need to explore reflection. It relates to manipulating metadata of .NET types (classes, structs, enums, etc). However, if you're running your app in shared hosting with partial trust, you may not be able to have any kind of reflection code run at all (security restriction on the server). If this is the case, test on a small/quick example first (on your hosting), and then make decisions appropriately: whether to redesign your app or change hosts.
A reflection-related snippet that might be useful to you (paste this somewhere within the user control class, as this.GetType() matters:
var properties = this.GetType().GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach (var p in properties)
{
string propertyName = p.Name;
}
There are other ways to get the type; e.g. typeof(yourclassname); you can also reflect/get all types from given assembly (dll), and much more.
Is there a way to obtain the object behind a property by reflection?
I am trying to manage a dynamic setting of a property.
Example:
class Animal
{
public string Name {get;set;}
public string Family {get;set;}
}
class Zoo
{
public Animal Lion {get;set;}
public Animal Panda {get;set;}
}
class Test
{
public void SetLionNameWithReflection()
{
Zoo londonZoo = new Zoo();
Type zooType = typeof(Zoo);
PropertyInfo lionProperty = zooType.GetProperty("Lion");
// Now what to write here so that I can manage to set Lion's name to Kaspar?
// (to manage this by reflection Lion.Name = "Kaspar");
}
}
What lines should I add more at the commented part above?
Thanks!
I don't think you actually need to know the object behind a property. Use the SetValue method to set its value to "Kaspar":
EDIT - as per dlev's comment, this is how it should look like:
Lion kaspar = new Lion { Name="Kaspar" };
zooType.SetValue(londonZoo, kaspar, null);
A property doesn't necessarily have an object "behind" it.
It's defined by 2 functions, get and set, that can do whatever you want, and not necessarily return an object's value at all.
What you used is just a syntactic sugar to make it easier to make a property to wrap a member.
No you can't use reflection to definitively get the object behind an arbitrary property. Largely because it's not guaranteed that every property is bound to an object. It could just as easily be a calculated value.
public class Student {
public string m_firstName;
public string m_lastName;
public string FullName {
get { return String.Format("{0} {1}", m_firstName, m_lastName); }
}
}
In this case the property FullName produces a calculated value and has no single backing object.
The case you're listing though is for auto-properties. There is likely a way to dig through the fields and use a form of name matching to get the one backing a given auto-property. However such a solution would be fragile to versioning and certainly not recomended.
Can you add an overloaded constructor to your animal object, which will allow you to pass in the animal name, like this?:
londonZoo.GetProperty("Lion").SetValue(londonZoo, new Lion("Kaspar"), null);
First you need to create the lion:
var lion = Activator.CreateInstance(lionProperty.PropertyType);
Then you need to set the Lion property of the zoo:
lionProperty.SetValue(londonZoo, lion, null);
Then you can get the Name property of the lion:
PropertyInfo property = lion.GetType().GetProperty("Name",
BindingFlags.Public | BindingFlags.Instance);
Then you can set its name:
if (property != null && property.CanWrite)
{
property.SetValue(lion, "Kaspar", null);
}