I have a custom attribute like this:
public class PropertyInfoAttribute : Attribute
{
public bool IsAutoComplete { get; set; }
}
And there is a class like this:
public class Article
{
public virtual int Order { get; set; }
//other properties
}
In another class,which inherits from Article, I override Order property and declare the attribute for it like this:
public class ArticleDetails : Article
{
[PropertyInfo(IsAutoCompele = true)]
public override int Order { get; set; }
}
The problem appears when I want to get attributes by using the GetCustomAttributes method in PropertyInfo class. I do it like this:
PropertyInfo propInfo = //do something for getting property info from the
//ArticleDetails class;
var attr = propInfo.GetCustomAttribute<PropertyInfoAttribute>();
But it returns nothing! I don't know why!
UPDATE:
I get property info in this method:
public static void InitPropertyInfoAttribute<TModel, TProperty>(MvcHtmlString source, Expression<Func<TModel, TProperty>> expression)
{
PropertyInfo propInfo = (expression.Body as MemberExpression).Member as PropertyInfo;
}
I think the problem hides in here:
PropertyInfo propInfo = //do something for getting property info from the
//ArticleDetails class;
I presume that you actually obtain this property info from Article class, not ArticleDetails and that's why it returns null. The following snippet worked as expected for me:
PropertyInfo propInfo = typeof(ArticleDetails).GetProperty("Order");
var attr = propInfo.GetCustomAttribute<PropertyInfoAttribute>();
Update
According to your update - the problem is that Member property of the MemberExpression points to the Article type;
As a solution to this you can update your InitPropertyInforAttribute as follows:
MemberExpression memberExpression = (expression.Body as MemberExpression);
return typeof(TModel).GetProperty(memberExpression.Member.Name);
And don't forget that you should pass ArticleDetails as first generic type parameter - InitPropertyInfoAttribute<ArticleDetails, propertyType>.
Sorry, but I can't reproduce the error. Attribute is extracted. Could you provide the details?
// Your classes
public class PropertyInfoAttribute: Attribute {
public bool IsAutoComplete {
get;
set;
}
}
public class Article {
public virtual int Order {
get;
set;
}
}
public class ArticleDetails: Article {
[PropertyInfo(IsAutoComplete = true)]
public override int Order {
get;
set;
}
}
...
// My test
// Let's do it explicitly:
// ask for public and instance (not static) property
PropertyInfo pi = typeof(ArticleDetails).GetProperty("Order", BindingFlags.Public | BindingFlags.Instance);
// Then ask for the attribute
Attribute at = pi.GetCustomAttribute(typeof(PropertyInfoAttribute));
// And, finally, check if attribute is existing
// ... And so, assertion passes - attribute is existing
Trace.Assert(!Object.ReferenceEquals(null, at), "No Attribute found.");
Related
I have a custom attribute, inside the constructor of my custom attribute I want to set the value of a property of my attribute to the type of the property my attribute was applied to, is there someway to access the member that the attribute was applied to from inside my attribute class?
It's possible from .NET 4.5 using CallerMemberName:
[SomethingCustom]
public string MyProperty { get; set; }
Then your attribute:
[AttributeUsage(AttributeTargets.Property)]
public class SomethingCustomAttribute : Attribute
{
public StartupArgumentAttribute([CallerMemberName] string propName = null)
{
// propName == "MyProperty"
}
}
Attributes don't work that way, I'm afraid. They are merely "markers", attached to objects, but unable to interact with them.
Attributes themselves should usually be devoid of behaviour, simply containing meta-data for the type they are attached to. Any behaviour associated with an attribute should be provided by another class which looks for the presence of the attribute and performs a task.
If you are interested in the type the attribute is applied to, that information will be available at the same time you are reflecting to obtain the attribute.
You can do next. It is simple example.
//target class
public class SomeClass{
[CustomRequired(ErrorMessage = "{0} is required", ProperytName = "DisplayName")]
public string Link { get; set; }
public string DisplayName { get; set; }
}
//custom attribute
public class CustomRequiredAttribute : RequiredAttribute, IClientValidatable
{
public string ProperytName { get; set; }
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
var propertyValue = "Value";
var parentMetaData = ModelMetadataProviders.Current
.GetMetadataForProperties(context.Controller.ViewData.Model, context.Controller.ViewData.Model.GetType());
var property = parentMetaData.FirstOrDefault(p => p.PropertyName == ProperytName);
if (property != null)
propertyValue = property.Model.ToString();
yield return new ModelClientValidationRule
{
ErrorMessage = string.Format(ErrorMessage, propertyValue),
ValidationType = "required"
};
}
}
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 am trying to figure out something with c# code, and I'm not 100% sure if it is possible, but I am trying to implement search functionality for several classes which is streamlined and overall easy to develop for. Right now I have the following code:
[DataContract(IsReference = true), Serializable]
public class ClassSearch
{
[DataMember]
public string Name { get; set; }
[DataMember]
public object Value { get; set; }
public override string ToString()
{
return String.Format("{0} = {1}", Name, Value);
}
... // additional logic
}
However, I would like to include strong typing for the object value so that it only can be set to the property that is passed in, I guess like similar (hypothetical, not sure if this would work)
[DataContract(IsReference = true), Serializable]
public class ClassSearch<TProperty>
{
[DataMember]
public TProperty Property {get; set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
... // additional logic
}
public class MainClass
{
public void Execute()
{
SomeClass someClass = new Class{
Property = "Value";
};
ClassSearch search = new ClassSearch<SomeClass.Property>{
Property = someClass.Property
};
var retString = search.ToString(); // Returns "Property = 'Value'"
}
}
It seems you are trying to create a WCF service to be able to pass any type you like.
First of all, this is not WSDL-friendly. All WCF services needs to be able to be exposed in WSDL. WSDL is all about well-defined contracts hence the types need be all defined. So that generic approach would not work - mainly because of WSDL. Having said that, you still can use generics but then you have to use KnownType and actually define all the types possible - which for me defeats the object.
Yet, one thing you can do is to serialize the object yourself and pass around with its type name across the wire. On the other side, you can pick it up deserialize.
So something along the line of:
// NOTE: Not meant for production!
[DataContract]
public class GenericWcfPayload
{
[DataMember]
public byte[] Payload {get; set;}
[DataMember]
public string TypeName {get; set;}
}
If there are no easier answers I would try it with this one.
You could use expressions like so:
// Sample object with a property.
SomeClass someClass = new SomeClass{Property = "Value"};
// Create the member expression.
Expression<Func<object /*prop owner object*/, object/*prop value*/>> e =
owner => ((SomeClass)owner).Property;
// Get property name by analyzing expression.
string propName = ((MemberExpression)e.Body).Member.Name;
// Get property value by compiling and running expression.
object propValue = e.Compile().Invoke(someClass);
You hand over your property by the member expression owner => ((SomeClass)owner).Property. This expression contains both information you need: property name and property value. The last two lines show you how to get name and value.
Following a larger example:
class MainClass
{
public static void Execute()
{
SomeClass someClass = new SomeClass{
Property = "Value"
};
var search = new ClassSearch(s => ((SomeClass)s).Property);
Console.Out.WriteLine("{0} = '{1}'", search.Property.Name, search.Property.GetValue(someClass));
}
}
class Reflector
{
public static string GetPropertyName(Expression<Func<object, object>> e)
{
if (e.Body.NodeType != ExpressionType.MemberAccess)
{
throw new ArgumentException("Wrong expression!");
}
MemberExpression me = ((MemberExpression) e.Body);
return me.Member.Name;
}
}
class ClassSearch
{
public ClassSearch(Expression<Func<object, object>> e)
{
Property = new PropertyNameAndValue(e);
}
public PropertyNameAndValue Property { get; private set; }
public override string ToString()
{
return String.Format("{0} = '{1}'", Property.Name, Property);
}
}
class PropertyNameAndValue
{
private readonly Func<object, object> _func;
public PropertyNameAndValue(Expression<Func<object, object>> e)
{
_func = e.Compile();
Name = Reflector.GetPropertyName(e);
}
public object GetValue(object propOwner)
{
return _func.Invoke(propOwner);
}
public string Name { get; private set; }
}
class SomeClass
{
public string Property { get; set; }
}
The main part of that example is the method Reflector.GetPropertyName(...) that returns the name of a property within an expression. I.e. Reflector.GetPropertyName(s => ((SomeClass)s).Property) would return "Property".
The advantage is: This is type-safe because in new ClassSearch(s => s.Property) compiling would end with an error if SomeClass would not have a property 'Property'.
The disadvantage is: This is not type-safe because if you write e.g. new ClassSearch(s => s.Method()) and there would be a method 'Method' then there would be no compile error but a runtime error.
I have a custom attribute that I apply to properties on a class. This attribute is used for exporting the class's properties to a flat file.
One of the attribute's properties is FieldOrder. I need to make sure the order in which I export the properties of the class is correct. Also, not all properties on the class will have the custom attribute.
I found this article: How do I sort a generic list based on a custom attribute? This solution assumes all properties have the custom attribute, which isn't my case. I was also hoping for more elegant solution.
Your help is greatly appreciated!
public interface IFileExport{}
public class ExportAttribute: Attribute
{
public int FieldOrder { get; set; }
public int FieldLength { get; set; }
public ExportAttribute() { }
}
public class ExportClass: IFileExport
{
[ExportAttribute( FieldOrder = 2, FieldLength = 25 )]
public string LastName { get; set; }
[ExportAttribute( FieldOrder=1, FieldLength=25)]
public string FirstName { get; set; }
[ExportAttribute( FieldOrder = 3, FieldLength = 3 )]
public int Age { get; set; }
public ExportClass() { }
}
public class TestClass
{
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder
(IFileExport fileExport)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport
.GetType()
.GetProperties( BindingFlags.Instance | BindingFlags.Public );
// now I need to figure out which properties have the ExportAttribute
//and sort them by the ExportAttribute.FieldOrder
}
}
UPDATE: I'm ordering the properties by ExportAttribute.FieldOrder Ascending
public static List<PropertyInfo> GetPropertiesSortedByFieldOrder( IFileExport fileExport )
{
PropertyInfo[] allProperties = GetType()
.GetProperties(BindingFlags.Instance | BindingFlags.Public)
.Select(x => new
{
Property = x,
Attribute = (ExportAttribute)Attribute.GetCustomAttribute(x, typeof(ExportAttribute), true)
})
.OrderBy(x => x.Attribute != null ? x.Attribute.FieldOrder : -1)
.Select(x => x.Property)
.ToArray();
}
Since you didn't explain how you wanted properties without the attribute ordered, I have made it so that they would be at the beginning. But the gist of this code is:
Get the properties
Throw them into an anonymous type so you have easy access to both the property and the attribute.
Order by the FieldOrder, using -1 for properties without the attribute. (not sure what you wanted here)
Transform the sequence back into a sequence of PropertyInfo
Convert it into a PropertyInfo[] array.
You can use either of the following options.
First option: pass anonymous function to OrderBy
return allProperties.OrderBy(m => m.GetCustomAttribute<ExportAttribute>() == null ? -1 :
m.GetCustomAttribute<ExportAttribute>().FieldOrder).ToList();
Second option: create the function for selecting the key and pass it to OrderBy
return allProperties.OrderBy(KeySelector).ToList();
The key selector function is defined as in here:
public static int KeySelector(PropertyInfo info)
{
ExportAttribute attr = info.GetCustomAttribute<ExportAttribute>();
return attr == null ? -1 : attr.FieldOrder;
}
If the property does not have ExportAttribute, the selector will return -1. You can choose any other default value.
The second approach lets you define other types of selectors for ordering and just call the new selector you have defined.
You should be able to use the GetCustomAttributes() method on each PropertyInfo to filter the properties with the correct attributes, and then sort the remaining items.
static void Main(string[] args)
{
//get all properties on the IFileExport object
PropertyInfo[] allProperties = fileExport.GetType().GetProperties(BindingFlags.Instance | BindingFlags.Public);
Array.Sort(allProperties, ArrayAttributeComparison);
}
private static int ArrayAttributeComparison(PropertyInfo x, PropertyInfo y)
{
//Do null checks here
ExportAttribute xExportAttribute = GetExportAtribute(x);
ExportAttribute yExportAttribute = GetExportAtribute(x);
//Do null checks here
return xExportAttribute.FieldOrder - yExportAttribute.FieldOrder;
}
private static ExportAttribute GetExportAtribute(PropertyInfo propertyInfo)
{
object[] attributes = propertyInfo.GetCustomAttributes(true);
foreach (var t in attributes)
{
if (t is ExportAttribute)
{
return (ExportAttribute)t;
}
}
return null;
}
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).