I have 2 classes
Class 1
public class baseClass
{
public string prop1{get;set;}
public string prop2{get;set;}
public string prop3{get;set;}
}
Class 2
public class derived:baseClass
{
public string prop4{get;set;}
}
Now when i try to read properties with the following code, but as its obvious it only returns derived class's properties
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(derived));
Is there any way with which i can read properties of derived as well as baseclass
Why not use Reflection?
PropertyInfo[] properties = typeof(derived).GetProperties(BindingFlags.Public | BindingFlags.Instance);
Console.Write(String.Join(Envrironment.NewLine, properties.Select(p => p.Name)));
Actually it works:
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(Derived));
for (int i = 0; i < properties.Count; i++)
{
Console.WriteLine(properties[i].Name);
}
Returns:
prop1 prop2 prop3 prop4
And as I have founded in http://referencesource.microsoft.com/, GetProperties() will internally call GetProviderRecursive:
/// <devdoc>
/// This method returns a type description provider, but instead of creating
/// a delegating provider for the type, this will walk all base types until
/// it locates a provider. The provider returned cannot be cached. This
/// method is used by the DelegatingTypeDescriptionProvider to efficiently
/// locate the provider to delegate to.
/// </devdoc>
internal static TypeDescriptionProvider GetProviderRecursive(Type type) {
return NodeFor(type, false);
}
I don't know for what purpose you are trying to fetch properties, but as #Dmitry Bychenko answered, you can use Reflection. You can check the differences of the both ways in this SO link.
Update to your answer:
var result = typeof(Derived).GetProperties()
.Select(prop => new
{
prop.Name,
prop.PropertyType
});
I found solution to read property name as well as its type
var properties = typeof(T).GetFields();
foreach (var prop in properties)
{
var name = prop.Name;
var type = Nullable.GetUnderlyingType(prop.FieldType.FullName) ?? prop.FieldType.FullName);
}
Related
I created some custom attribute to apply it on a class member:
[
System.AttributeUsage(
AttributeTargets.Field | AttributeTargets.Property, AllowMultiple = true
)
]
internal class ActionAttribute : Attribute
{
private Action action;
public ActionAttribute(Action action)
{
this.action = action;
}
public Action getThis()
{
return this.action;
}
}
But am struggling on how to retrieve it's value using reflection.
This is my attempt:
public static Device Serialize(string deviceName, Dictionary<string, dynamic> fields)
{
var itce = devices[deviceName];
Type objectType = itce.GetType();
MemberInfo[] fieldsInfo = objectType.GetMembers();
foreach (var field in fieldsInfo.Where(p => p.MemberType == MemberTypes.Property))
{
Console.WriteLine(field.Name);
object[] actionAttributes = field.GetCustomAttributes(typeof(ActionAttribute), false);
foreach (var cAttr in actionAttributes)
{
Console.WriteLine("Attrs: " + cAttr.GetType());
}
}
return itce;
}
Where in the variable itce I just retrieve a previously allocated instance of a type that contains those attributes using a factory pattern.
The thing I want it's is actual value, but I only can read it's class definition full name. It's obvious, I am asking for it to the GetType() method, but I have only four opts available like ToString() and things like that. I am imagine that I am missing some type cast probably? Don't know. Hope someone could help me with this.
BTW, Action type it's just an enum:
enum Action
{
Read,
Write
}
and, a simple example of the usage of the attributes:
public class Device : Display
{
[Action(Action.Read)]
[Action(Action.Write)]
public string device_name { get; set; }
public Device(string device_name)
{
this.device_name = device_name;
}
}
So, the idea, it's to retrieve the value of the attribute whenever a type has a field annotated. Above, Device has two annotations, Read and Write. I want to recover with reflection the actual value or values attached to that field.
device_name has two attributes, so I need to recover Action.Read and Action.Write.
Thanks.
As #freakish pointed, solution it's pretty straightfoward.
object[] actionAttributes = field.GetCustomAttributes(typeof(ActionAttribute), false);
foreach (var cAttr in actionAttributes)
{
var attr = (ActionAttribute)cAttr;
Console.WriteLine("Attrs: " + attr.getThis());
}
Casting the var cAttr to the attribute type allows me to easily access the info that holds the field attribute.
Instead of using var for your loop control variable and it being object, specify the type as your attribute:
object[] actionAttributes = field.GetCustomAttributes(typeof(ActionAttribute), false);
foreach (ActionAttribute cAttr in actionAttributes)
{
Console.WriteLine("Attrs: " + cAttr.getThis());
}
Of course, you really ought to be using a public read-only property, rather than a private field and a method, to access that value.
I want to get a list of fields with an Attribute Sync.Field on each of the field in the class. The field can / cannot have the attribute of Sync.Field
I have been trying the following, but having trouble getting the custom attribute for each field.
FieldInfo[] fiClass = typClass.GetFields();
FieldInfo[] lst = fiClass
.Where(c => c.CustomAttribute().GetType() == typeOf(Sync.Field))
.ToList();
I have a generic collection class, which uses a data class to match an SNMP table with data class fields. Like JsonProperty matches deserialised values to properties. In the same way I define a SNMPPropertyAttribute. The attribute itself is
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
sealed class SNMPPropertyAttribute : Attribute
{
public SNMPPropertyAttribute(string propertyOID) => PropertyOID = new ObjectIdentifier(propertyOID);
public ObjectIdentifier PropertyOID { get; }
}
When in the table constructor, I'm making a dictionary of data fiels and their OIDs from the attribute:
public SNMPTableEntity()
{
snmpPoperties = new Dictionary<ObjectIdentifier, PropertyInfo>();
foreach (PropertyInfo myProperty in GetType().GetProperties(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public))
{
CustomAttributeData snmpAttribure = myProperty.CustomAttributes.Where(x => x.AttributeType == typeof(SNMPPropertyAttribute)).FirstOrDefault();
if (snmpAttribure != null)
snmpPoperties.Add(new ObjectIdentifier((string)snmpAttribure.ConstructorArguments[0].Value), myProperty);
}
}
It looks similar to what are you trying to acheive, so hopefully it helps. But the difference, is that I'm using properties, not fields. Not sure if it makes a big difference, but...
There is an example of using:
public class InterfaceTableEntity : SNMPTableEntity
{
/// <summary>
/// A unique value for each interface. Its value ranges between 1 and the value of ifNumber. The value for each interface must remain constant at least from one re-initialization of the entity's network management system to the next re- initialization.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.1")]
protected Integer32 ifIndex { get; set; }
/// <summary>
/// A textual string containing information about the interface. This string should include the name of the manufacturer, the product name and the version of the hardware interface.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.2")]
protected OctetString ifDescr { get; set; }
/// <summary>
/// The type of interface, distinguished according to the physical/link protocol(s) immediately `below' the network layer in the protocol stack.
/// </summary>
[SNMPProperty("1.3.6.1.2.1.2.2.1.3")]
protected Integer32 ifType { get; set; }
}
If you have the FieldInfo, you can get an instance of its attribute using this code:
var attr = fieldInfo.GetCustomAttributes().OfType<Sync.FieldAttribute>().SingleOrDefault();
See my example on DotNetFiddle.
I have a class that contains multiple string fields. Whenever an object of this class is instantiated, I'd like those fields to be automatically assigned with the same specific default value (something like "Undefined"). The reason is:
If I have to serialize the object before all fields are populated with real data, I want those fields to display as this default value rather than being null or string.Empty.
String fields may be added/removed from this class as the project progresses. I'd like to not have to touch the constructor every time that occurs.
Is there any way to do this other than explicitly assigning the default value to each of the string fields one by one in the class constructor?
In C# 6.0 and above, you can use Auto-Property Initializer:
https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-6#auto-property-initializers
Basically:
public string Property { get; set; } = "UNDEFINED";
You would have to use reflection. Something like this
Type type = obj.GetType();
PropertyInfo[] properties = type.GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(string)) property.setValue(obj, "UNDEFINED");
}
First of all: I don't see how it could be best practice to do what you want.
If you want something like this to show up in your code:
public string Property { get; set; } = "UNDEFINED";
You should probably look into creating custom snippets that simply write exactly that. e.g. https://msdn.microsoft.com/en-us/library/ms165394.aspx
If you don't want that, you could use reflection to find all fields (e.g. strings) in the constructor and set them.
C# Reflection - Get field values from a simple class
FieldInfo[] fields = data.GetType().GetFields(BindingFlags.Public |
BindingFlags.NonPublic |
BindingFlags.Instance);
Setting a property by reflection with a string value
Ship ship = new Ship();
string value = "5.5";
PropertyInfo propertyInfo = ship.GetType().GetProperty("Latitude");
propertyInfo.SetValue(ship, Convert.ChangeType(value, propertyInfo.PropertyType), null);
Well, why not have an extension method like
public static class MyClass
{
public static string GetDefault(this str, string defaultVal)
{
return string.IsNullOrEmpty(str) ? defaultVal : str;
}
}
For a type
public class SomeClass
{
public string str = string.Empty;
}
You can call
SomeClass s = new SomeClass();
s.str.GetDefault("UNDEFINED");
You can initialize values to fields directly instead of in the constructor.
private string myStringVariable = "UNDEFINED";
Perhaps you should reconsider the structure of your program though if it permits many fields to be initialized to undefined.
Maybe I am misunderstanding this but why not do word for word what you described in the question in your constructor?
public class Weee
{
public string name { get; set; }
public int order { get; set; }
public string whatever { get; set; }
public Weee()
{
foreach(var p in typeof(Weee).GetProperties().Where(a => a.PropertyType == typeof(string)))
{
p.SetValue(this, "wut");
}
}
}
You can create a property initializer and have a base class use it. Your classes can then inherit from the base and have their properties automatically initialized:
public class PropertyInitializer
{
public void Initialize<T>(object obj, T value)
{
PropertyInfo[] properties = obj.GetType().GetProperties();
foreach (PropertyInfo property in properties)
{
if (property.PropertyType == typeof(T))
{
property.SetValue(obj, value);
}
}
}
}
public class InitializedBase
{
protected InitializedBase()
{
var initializer = new PropertyInitializer();
//Initialize all strings
initializer.Initialize<string>(this, "Juan");
//Initialize all integers
initializer.Initialize<int>(this, 31);
}
}
//Sample class to illustrate
public class AutoInitializedClass : InitializedBase
{
public string Name { get; set; }
public int Age { get; set; }
public override string ToString()
{
return string.Format("My name is {0} and I am {1} years old", Name, Age);
}
}
Sample usage:
AutoInitializedClass sample = new AutoInitializedClass();
Console.WriteLine(sample);
Console output:
My name is Juan and I am 31 years old
Notice the base class is using the PropertyInitializer class to initialize fields. This is a simplified example. You can expand it as it fits you (it may not work out of the box with all types).
I personally don't recommend this. It's called a constructor for a reason but you asked a question and I provided an answer.
Here is a simple class from which you can inherit that does exactly what you want:
Example usage:
public class MyClass : DefaultedObject<string>
{
public string MyStringField;
protected override string Default => "UNDEFINED";
}
var myClass = new MyClass();
// myClass.MyStringField == "UNDEFINED"
Implementation:
public abstract class DefaultedObject<T>
{
protected DefaultedObject()
{
T defaultValue = Default;
FieldInfo[] fields = GetType().GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
foreach(FieldInfo field in fields) {
if(field.FieldType == typeof(T)) {
field.SetValue(this, defaultValue);
}
}
}
protected abstract T Default { get; }
}
I appreciate all the feedback to this question. Here's what ended up working. First, for any string attributes in the class that I wanted to receive an automatic default value, I established as a property:
public string attribute1 {get; set;}
public string attribute2 {get; set;}
And so on. Then, in the class constructor, I included the following loop which iterates through each property of type string:
foreach(PropertyInfo property in GetType().GetProperties())
{
if (property.PropertyType == typeof(string))
property.SetValue(this, "UNDEFINED"));
}
This produced the desired outcome for me.
I'm using reflection to iterate over all the members of a given type. This interaction must support inheritance, since most type will be extended as necessary.
I've just found out that the order in which types present themselves when iterating over GetMembers isn't really what I'd expect -- the types of the derived classes appear first, in their current order, and the types of the base classes later, again in their current order.
Source:
using System;
class Program
{
class SomeClass
{
public string First { get; set; }
public int Second;
}
class AnotherClass : SomeClass
{
public int Third { get; set; }
public string Fourth;
}
public static void Main()
{
var obj = new AnotherClass { First = "asd", Second = 10};
foreach (var member in obj.GetType().GetMembers())
{
Console.WriteLine(member.Name);
}
}
}
Output:
get_Third
set_Third
get_First
set_First
Equals
GetHashCode
GetType
ToString
.ctor
Third
First
Fourth
Second
You can check a run here.
I'd like to invert this situation, using reflection to get only types from the base class, then from the derived. Is there any way to do this?
Another question on the same line: when searching members, properties come first and fields second. Anyway to change this behavior as well, or the metadata created will always present in that order?
Thanks!
To access the base type use BaseType property.
To check if a member is declared in the same type, use DeclaringType property:
public static bool DeclaredInType(Type typeToCheck, MemberInfo member)
{
return typeToCheck.Equals(member.DeclaringType);
}
EDIT: you can sort by type by using LINQ:
public static MemberInfo[] SortMembers(IEnumerable<MemberInfo> members)
{
return members.OrderBy(m => m.GetType().Name)
.ToArray();
}
This is not exactly an answer to the OP (and I'm a bit late for that), but I'll just describe what I did, in the hopes someone may find it helpful.
I have a home-made program that serializes to XML. It is driven by a List of CopierField objects that I create that contain the data I need to expedite the serialization. Here is a much-redacted version of that class:
private class CopierField
{
// Name of the field or property and a reference to the declaring Type
public string MemberName;
public Type DeclaringType;
// Reference to the FieldInfo or PropertyInfo object for this field or property. One of
// these will be null and the other non-null.
public FieldInfo MemberInfoForField = null;
public PropertyInfo MemberInfoForProperty = null;
// Ordering of this field, as returned by Type.GetMembers(). This is only used while
// building the List<> of these objects for XML serialization
public int FieldOrder;
/// <summary>
/// Comparison method that can be used to sort a collection of CopierField objects so they
/// are in the order wanted for XML serialization. This ordering is dependent on the depth
/// of derivation, and when that is equal it maintains the original ordering.
/// </summary>
public static readonly Comparison<CopierField> CompareForXml =
delegate(CopierField a, CopierField b)
{
int aDepth = GetTypeDepth(a.DeclaringType);
int bDepth = GetTypeDepth(b.DeclaringType);
if (aDepth != bDepth)
return aDepth.CompareTo(bDepth);
return a.FieldOrder.CompareTo(b.FieldOrder);
};
/// <summary>
/// Method to determine the depth of derivation for a type.
/// </summary>
private static int GetTypeDepth(Type aType)
{
int i = 0;
while (aType.BaseType != null)
{
i++;
aType = aType.BaseType;
}
return i;
}
}
Before serializing an object type to XML the first time I create a List of these objects sorted in the order I want using a method somewhat like this, where the input is a List of the CopierField objects that is based on data from Type.GetMembers().
private static List<CopierField> CreateCopierFieldListForXml(List<CopierField> copierFields)
{
// Build the new list, and note the original ordering as created by Type.GetMembers()
List<CopierField> copierFieldsForXml = new List<CopierField>(copierFields.Count);
for (int listIndex = 0; listIndex < copierFields.Count; listIndex++)
{
CopierField copierField = copierFields[listIndex];
copierField.FieldOrder = listIndex;
copierFieldsForXml.Add(copierField);
}
// Sort the new list as wanted for XML serialization
copierFieldsForXml.Sort(CopierField.CompareForXml);
return copierFieldsForXml;
}
TL;DR
orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1
will push base memberInfo first, and keep the order defined in the class.
Full answer:
to achieve the same goal, and using the DeclaringType as suggested previously, I defined the following method:
public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClass<T>()
{
return
from mi in typeof(T).GetMembers(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static)
let ignoreAttr = (IgnoreSerializationAttribute)Attribute.GetCustomAttribute(mi, typeof(IgnoreSerializationAttribute))
where (mi.MemberType == MemberTypes.Field || mi.MemberType == MemberTypes.Property)
&& (ignoreAttr == null || ignoreAttr != null && !ignoreAttr.Ignore)
orderby typeof(T).Equals(mi.DeclaringType) ? 1 : -1
select mi;
}
In that method, I also defined a custom attribute to explicitely ignore some properties from the serialization:
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class IgnoreSerializationAttribute : Attribute
{
public bool Ignore { get; private set; }
public IgnoreSerializationAttribute(bool ignore)
{
Ignore = ignore;
}
}
It is also possible to add an other custom Attribute to define the order, e.g.
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ColumnOrderAttribute : Attribute
{
public int Order { get; private set; }
public ColumnOrderAttribute(int order)
{
Order = order;
}
}
used as follow:
public static IEnumerable<MemberInfo> GetAllFieldsAndPropertiesOfClassOrdered<T>()
{
return
from mi in GetAllFieldsAndPropertiesOfClass<T>()
let orderAttr = (ColumnOrderAttribute)Attribute.GetCustomAttribute(mi, typeof(ColumnOrderAttribute))
orderby orderAttr == null ? int.MaxValue : orderAttr.Order, mi.Name
select mi;
}
I am using those methods to serialize list of objects using other objects to CSV files...
I would like to automatically generate SQL statements from a class instance. The method should look like Update(object[] Properties, object PrimaryKeyProperty). The method is part of an instance (class, base method - generic for any child). Array of properties is an array of class properties, that will be used in update statement. Property names are equal to table field names.
The problem is that I can't get property names.
Is there any option to get a property name inside class instance?
sample:
public class MyClass {
public int iMyProperty { get; set; }
public string cMyProperty2 { get; set; }
{
main() {
MyClass _main = new MyClass();
_main.iMyProperty.*PropertyName* // should return string "iMyProperty"
{
I am aware of PropertyInfo, but I don't know hot to get the ID of a property from GetProperties() array.
Any suggestion?
Just wrote an implementation of this for a presentation on lambdas for our usergroup last Tuesday.
You can do
MembersOf<Animal>.GetName(x => x.Status)
Or
var a = new Animal()
a.MemberName(x => x.Status)
the code:
public static class MembersOf<T> {
public static string GetName<R>(Expression<Func<T,R>> expr) {
var node = expr.Body as MemberExpression;
if (object.ReferenceEquals(null, node))
throw new InvalidOperationException("Expression must be of member access");
return node.Member.Name;
}
}
Link to the presentation and code samples.
Also in SVN (more likely to be updated): http://gim-projects.googlecode.com/svn/presentations/CantDanceTheLambda
I found a perfect solution in This Post
public static string GetPropertyName<T>(Expression<Func<T>> propertyExpression)
{
return (propertyExpression.Body as MemberExpression).Member.Name;
}
And then for the usage :
var propertyName = GetPropertyName(
() => myObject.AProperty); // returns "AProperty"
Works like a charm
You can do something like this:
Type t = someInstance.getType();
foreach (MemberInfo mi in t.GetMembers())
{
if (mi.MemberType == MemberTypes.Property)
{
Console.WriteLine(mi.Name);
}
}
to get all the property names for instance's type.
You can get the name (I assume that's what you meant by ID) of a property using PropertyInfo.Name. Just loop through the PropertyInfo[] returned from typeof(className).GetProperties()
foreach (PropertyInfo info in typeof(MyClass).GetProperties())
{
string name = info.Name;
// use name here
}
Since you already have an explicit handle to the specific property you want, you know the name - can you just type it?
Not 100% sure if this will get you what you're looking for, this will fetch all properties with [Column] attribute inside your class:
In the datacontext I have:
public ReadOnlyCollection<MetaDataMember> ColumnNames<TEntity>( )
{
return this.Mapping.MappingSource.GetModel(typeof(DataContext)).GetMetaType(typeof(TEntity)).DataMembers;
}
Fetching the table column-names that are properties inside the class:
MyDataContext db = GetDataContext();
var allColumnPropertyNames = db.ColumnNames<Animal>().Where(n => n.Member.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute), false).FirstOrDefault() != null).Select(n => n.Name);
Let's say (from the first sample, method update of a class MyClass):
public class MyClass {
public int iMyStatusProperty { get; set; }
public int iMyKey { get; set; }
public int UpdateStatusProperty(int iValue){
this.iMyStatusProperty = iValue;
return _Update( new[iMyStatusProperty ], iMyKey); // this should generate SQL: "UPDATE MyClass set iMyStatusProperty = {iMyStatusProperty} where iMyKey = {iMyKey}"
}
{iMyStatusProperty} and {iMyKey} are property values of a class instance.
So, the problem is how to get property name (reflection) from a property without using names of properties as strings (to avoid field name typos).