How to get PropertyDescriptor for current property? - c#

How can I get the PropertyDescriptor for the current property? For example:
[MyAttribute("SomeText")]
public string MyProperty
{
get{....}
set
{
// here I want to get PropertyDescriptor for this property.
}
}

You could try this:
public string Test
{
get
{
//Get properties for this
System.ComponentModel.PropertyDescriptorCollection pdc = System.ComponentModel.TypeDescriptor.GetProperties( this );
//Get property descriptor for current property
System.ComponentModel.PropertyDescriptor pd = pdc[ System.Reflection.MethodBase.GetCurrentMethod().Name ];
}
}

Here's a re-usable conversion function for those who got to this post looking for a general function:
public static PropertyDescriptor GetPropertyDescriptor(PropertyInfo PropertyInfo)
{
return TypeDescriptor.GetProperties(PropertyInfo.DeclaringType).Item(PropertyInfo.Name);
}
and here's an extension method:
public static PropertyDescriptor PropertyDescriptor(this PropertyInfo propertyInfo)
{
return TypeDescriptor.GetProperties(propertyInfo.DeclaringType)[propertyInfo.Name];
}

I found that the following worked:
// get property descriptions
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties ( this );
// get specific descriptor
PropertyDescriptor property = properties.Find ( PropertyName, false );
where PropertyName is a value passed into a method.

How about this?
this.GetType().GetProperty("MyProperty")
I think you're asking if you can do this without the string - i.e. some other token that represents 'this property'. I don't think that exists. But since you are writing this code anyway (?) what is the difficulty in just putting the name of the property in the code?

For future reference, you can now do this:
public static PropertyDescriptor? GetPropertyDescriptor(
this object target,
[CallerMemberName] string propertyName = ""
) => TypeDescriptor.GetProperties(target.GetType())
.Find(propertyName, ignoreCase: false)

Related

C# Attribute check is an value equals the constructor argument and get constructor values

How can i check that some string is equal to the "constructor" arguments of an attribute?
And how to get all constructor values (TestArg1, TestArg2)?
struct MyData
{
[MyAttr("TestArg1", "TestArg2")] //check that some string equals TestArg1/TestArg2
public string TestArg;
}
This primarily depends on what attribute you're looking at and how it's coded. See the code below as an example on how to do what you're asking.
//The attribute we're looking at
public class MyAtt : System.Attribute
{
public string name;
public string anotherstring;
public MyAtt(string name, string anotherstring)
{
this.name = name;
this.anotherstring = anotherstring;
}
}
public static class Usage
{
[MyAtt("String1", "String2")] //Using the attribute
public static string SomeProperty = "String1";
}
public static class Program
{
public static void Main()
{
Console.WriteLine(IsEqualToAttribute("String1"));
Console.WriteLine(IsEqualToAttribute("blah"));
Console.ReadKey();
}
public static bool IsEqualToAttribute(string mystring)
{
//Let's get all the properties from Usage
PropertyInfo[] props = typeof(Usage).GetProperties();
foreach (var prop in props)
{
//Let's make sure we have the right property
if (prop.Name == "SomeProperty")
{
//Get the attributes from the property
var attrs = prop.GetCustomAttributes();
//Select just the attribute named "MyAtt"
var attr = attrs.SingleOrDefault(x => x.GetType().Name == "MyAtt");
MyAtt myAttribute = attr as MyAtt; //Just casting to the correct type
if (myAttribute.name == mystring) //Compare the strings
return true;
if (myAttribute.anotherstring == mystring) //Compare the strings
return true;
}
}
return false;
}
}
As you can see we get the attribute off the property using reflection and then just compare the properties.
More info can be found here:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/attributes/accessing-attributes-by-using-reflection
As far as getting the constructor properties something along the lines of
typeof(MyAtt).GetConstructor().GetParameters()
Would retrieve the parameter details for the constructor.
There is also info on this in the Microsoft Docs: https://learn.microsoft.com/en-us/dotnet/api/system.reflection.customattributedata.constructor?view=netframework-4.7.2
Here is one way to do what you are asking for, but it's not particularly scaleable and requires a bunch of manual code to get working but may get you on the road to what you are trying to achieve. Assuming we have an attribute something like this that takes a string array in it's constructor:
public class MyAttrAttribute : Attribute
{
public string[] AllowedValues { get; }
public MyAttrAttribute(params string[] values)
{
AllowedValues = values;
}
}
You can change your field to be a property with a backing field. This allows you to override the set method and do your checking in there:
private string _testArg;
[MyAttr("TestArg1", "TestArg2")] //check that some string equals TestArg1/TestArg2
public string TestArg
{
get => _testArg;
set
{
var allowedValues = this.GetType() //Get the type of 'this'
.GetProperty(nameof(TestArg)) // Get this property
.GetCustomAttribute<MyAttrAttribute>() // Get the attribute
.AllowedValues; //Get the allowed values specified in the attribute
if(!allowedValues.Contains(value))
{
throw new ArgumentOutOfRangeException(nameof(value),
$"The value '{value}' is not allowed");
}
_testArg = value;
}
}
Having said all of this, I firmly believe that there is a better way to achieve what you are asking. For example, if you are restricted to a minimal set of values, then an enum would almost certainly be a better option than a string.

Getting value of static property by string name

There's a great post here that gives a way to get the value of a property by its string name:
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
Currently, I'm trying to get the value of a static property in a base class. If I try to use BaseClass.Prop as 'src', however, I get a null reference exception. While src isn't associated with an explicit instance, the value of Prop I'm trying to get nevertheless still exists.
Is there a workaround for static properties?
Don't send a src when calling static properties.
Type t = src.GetType();
if (t.GetProperty(propName).GetGetMethod().IsStatic)
{
src = null;
}
return t.GetProperty(propName).GetValue(src, null);
To get a static property, you cannot pass an object reference. To detect if a property-get is static, look at propertyInfo.GetGetMethod().IsStatic. Here's your GetPropValue method:
public static object GetPropValue(object src, string propName)
{
var propertyInfo = src.GetType().GetProperty(propName);
if (propertyInfo.GetGetMethod().IsStatic)
return propertyInfo.GetValue(null, null);
else
return propertyInfo.GetValue(src, null);
}

Object with user-configurable property "visibility"

I have a User object with a bunch of properties. I have a requirement that states when a user sets up their information, they need the ability to state which properties of their profile are visible to others.
The way I had envisioned this was adding an additional property - a list of string that would contain the property names that were publicly visible. I could then implement a method called ToPublicView() or something similar that would use reflection to set non-public properties to null or default.
Is this a reasonable approach, or is there a better way?
I think it's the simplest of the options. If reflection start to kill your performance, you may want to have a dictionary of property-delegate for accessing the values.
And as the requirement is not to have dynamic properties but just to mark the existing ones, it doesn't make sense to have all the properties in a dynamic way (like a list of property objects). Also, having them as actual properties will make the code more readable when you have to use it for the rest of the application.
In such a situation, if possible, I would suggest simply having a list of your properties, such as:
public Class Property<T>
{
public Property(string name, bool visible, T value)
{
Name = name;
Visible = visible;
Value = value;
}
string Name { get; set; }
bool Visible { get; set; }
T Value { get; set; }
}
Then you could create a list of the properties like this:
List<Property> properties = new List<Property>();
properties.Add(new Property<string>("FirstName", true, "Steve"));
If you need to be able to set the visibility today, you may need to set other meta-properties as well tomorrow. Color? Required/Optional? Size? Etc. Having your own Property type allows you to easily expand it in the future.
What? No. If that's the demand, then User properties should not be realized with actual properties, but instead using some sort of IEnumerable and Property objects, where each Property has its visibility, etc.
Can use, may be, some combination of custom DynamicObject implementation
EDIT
//custom property class
public class MyProperty
{
public bool IsVisible { get; set; }
public string PropertyName { get; set; }
}
public class Dymo: DynamicObject
{
Dictionary<MyProperty, object> dictionary
= new Dictionary<MyProperty, object>();
public override bool TryGetMember(
GetMemberBinder binder, out object result)
{
result = false;
var prop = PropertyFromName(binder.Name);
if (prop != null && prop.IsVisible)
return dictionary.TryGetValue(prop, out result);
return false;
}
public override bool TrySetMember(
SetMemberBinder binder, object value)
{
var prop = PropertyFromName(binder.Name);
if (prop != null && prop.IsVisible)
dictionary[prop] = value;
else
dictionary[new MyProperty { IsVisible = true, PropertyName = binder.Name}] = value;
return true;
}
private MyProperty PropertyFromName(string name)
{
return (from key in dictionary.Keys where key.PropertyName.Equals(name) select key).SingleOrDefault<MyProperty>();
}
public void SetPropertyVisibility(string propertyName, bool visibility)
{
var prop = PropertyFromName(propertyName);
if (prop != null)
prop.IsVisible = visibility;
}
}
and use this, after like this.
dynamic dynObj = new Dymo();
dynObj.Cartoon= "Mickey" ;
dynObj.SetPropertyVisibility("Mickey", false); //MAKE A PROPERTY "INVISIBLE"

Set objects properties from string in C#

Is there any way to set the properties of the objects from string. For example I have "FullRowSelect=true" and "HoverSelection=true" statements as string for ListView property.
How to assign these property along with their values without using if-else or switch-case statments? Is there any SetProperty(propertyName,Value) method or similar for this?
Try this:
private void setProperty(object containingObject, string propertyName, object newValue)
{
containingObject.GetType().InvokeMember(propertyName, BindingFlags.SetProperty, null, containingObject, new object[] { newValue });
}
You can use reflection to do this:
myObj.GetType().GetProperty("FullRowSelect").SetValue(myObj, true, null);
You can do this with reflection, have a look at the PropertyInfo class's SetValue method
YourClass theObject = this;
PropertyInfo piInstance = typeof(YourClass).GetProperty("PropertyName");
piInstance.SetValue(theObject, "Value", null);
Try this:
PropertyInfo pinfo = this.myListView.GetType().GetProperty("FullRowSelect");
if (pinfo != null)
pinfo.SetValue(this.myListView, true, null);
First variant is to use reflection:
public class PropertyWrapper<T>
{
private Dictionary<string, MethodBase> _getters = new Dictionary<string, MethodBase>();
public PropertyWrapper()
{
foreach (var item in typeof(T).GetProperties())
{
if (!item.CanRead)
continue;
_getters.Add(item.Name, item.GetGetMethod());
}
}
public string GetValue(T instance, string name)
{
MethodBase getter;
if (_getters.TryGetValue(name, out getter))
return getter.Invoke(instance, null).ToString();
return string.Empty;
}
}
to get a property value:
var wrapper = new PropertyWrapper<MyObject>(); //keep it as a member variable in your form
var myObject = new MyObject{LastName = "Arne");
var value = wrapper.GetValue(myObject, "LastName");
You can also use Expression class to access properties.
There isn't such a method, but you could write one using reflection.
You can look at Reflection. Its possible to find property and set its value thanks to this. But you need to parse your string yourself. And it may be problem geting valid value of correct type from string.
This can be accomplished with reflection, for example look at this question.

How to check if property setter is public

Given a PropertyInfo object, how can I check that the setter of the property is public?
Check what you get back from GetSetMethod:
MethodInfo setMethod = propInfo.GetSetMethod();
if (setMethod == null)
{
// The setter doesn't exist or isn't public.
}
Or, to put a different spin on Richard's answer:
if (propInfo.CanWrite && propInfo.GetSetMethod(/*nonPublic*/ true).IsPublic)
{
// The setter exists and is public.
}
Note that if all you want to do is set a property as long as it has a setter, you don't actually have to care whether the setter is public. You can just use it, public or private:
// This will give you the setter, whatever its accessibility,
// assuming it exists.
MethodInfo setter = propInfo.GetSetMethod(/*nonPublic*/ true);
if (setter != null)
{
// Just be aware that you're kind of being sneaky here.
setter.Invoke(target, new object[] { value });
}
.NET properties are really a wrapping shell around a get and set method.
You can use the GetSetMethod method on the PropertyInfo, returning the MethodInfo referring to the setter. You can do the same thing with GetGetMethod.
These methods will return null if the getter/setter is non-public.
The correct code here is:
bool IsPublic = propertyInfo.GetSetMethod() != null;
public class Program
{
class Foo
{
public string Bar { get; private set; }
}
static void Main(string[] args)
{
var prop = typeof(Foo).GetProperty("Bar");
if (prop != null)
{
// The property exists
var setter = prop.GetSetMethod(true);
if (setter != null)
{
// There's a setter
Console.WriteLine(setter.IsPublic);
}
}
}
}
You need to use the underling method to determine accessibility, using PropertyInfo.GetGetMethod() or PropertyInfo.GetSetMethod().
// Get a PropertyInfo instance...
var info = typeof(string).GetProperty ("Length");
// Then use the get method or the set method to determine accessibility
var isPublic = (info.GetGetMethod(true) ?? info.GetSetMethod(true)).IsPublic;
Note, however, that the getter & setter may have different accessibilities, e.g.:
class Demo {
public string Foo {/* public/* get; protected set; }
}
So you can't assume that the getter and the setter will have the same visibility.

Categories

Resources