Get Properties of baseclass and specific inherited class - c#

I have a base class CrmObject and a few classes that inherit it (Aufgabe, Kontakt, ...). I only have a string-value for the child-class and I want to get both the Properties of CrmObject and the specific child-class in one Statement.
I'd get the properties of the child-class like this:
var propertyInfos = typeof(CrmObject).Assembly.GetType("Aufgabe").GetProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
But I'd like to get the Properties of CrmObject, too. Possibly within the same statement.
[UPDATE]
This should be it. I'll test it later. Thank you, guys. :)
var propertyInfos = typeof(CrmObject).Assembly.GetType("DAKCrmImport.Core." +crmType).G‌​etProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
Weirdly enough you don't need the bindingflag parameter to flatten the hierarchy. Apparently it's the default value? Well .. whatever. It works :)

Works fine for me.
public class CrmObject
{
[ImportParameter]
public string Name { get; set; }
}
public class Aufgabe : CrmObject
{
[ImportParameter]
public int Id { get; set; }
}
public class ImportParameterAttribute : Attribute
{
}
public class InheritenceProgram
{
public static void Main()
{
var propertyInfos = typeof(CrmObject).Assembly.GetType("Aufgabe").GetProperties().Where(p => Attribute.IsDefined(p, typeof(ImportParameterAttribute)));
var list = propertyInfos.ToList();
}
}

As Mark said, you need to specify BindingFlags.FlattenHierarchy.
But when you specify the BindingFlags, you need to specify exactly what you want. That means that you also have to specify BindingFlags.Instance to get the instance members and BindingFlags.Public to include public members.
So the command would look like this:
var propertyInfos = typeof(CrmObject).Assembly.GetType(crmType).G‌​etProperties(BindingFlags.FlattenHierarchy | BindingFlags.Instance | BindingFlags.Public).Where(p => Attribute.IsDefined(p, typeof(ImportParameter)));
You can read more about it in this great SO answer and in the documentation of Type.GetProperties.

Related

C# Dynamically assign a specific default value to all fields of a certain type in new object instances?

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.

How to share a static method amongst several class

I'd like to start with something like this:
class A { ... }
class B { ... }
class C { ... }
Where A, B and C have a static method MyName.
Then I could do:
Console.WriteLine(A.MyName());
Console.WriteLine(B.MyName());
Console.WriteLine(C.MyName());
Then after I should be able to do something like this.
foreach(var type in new[] { typeof(A), typeof(B), typeof(C)) {
??? Console.WriteLine(t.MyName());
}
How could I do that?
I'd also like to be able to do the following (but that may be impossible):
??? x = new A();
Console.WriteLine(x.MyName());
x = new B();
Console.WriteLine(x.MyName());
What you're trying to do here is associate Metadata with a type, which can be queried if you know the type. The standard practice for doing this is to use Custom Attributes. You can query these attributes in a type-safe way and extract the associated information for each attribute. They are quite flexible in how you specify their inheritance and whether you can apply more than one of the same attribute type. They can also be applied to other things besides classes, like properties or fields, which can be handy.
Here's a simple demo program (the null check isn't strictly necessary here, but just demonstrating how you check whether an attribute actually exists.) Note that the extension method that provides a generic GetCustomAttribute was only added in .NET 4.5. Prior versions will require you to use a non-generic version and cast it to the appropriate attribute type.
class Program
{
static void Main(string[] args)
{
var types = new[] {typeof(A), typeof(B), typeof(C)};
foreach (var type in types)
{
var attribute = type.GetCustomAttribute<NameAttribute>();
if (attribute != null)
Console.WriteLine(attribute.Name);
}
Console.ReadLine();
}
public sealed class NameAttribute : Attribute
{
public string Name { get; private set; }
public NameAttribute(string name)
{
Name = name;
}
}
[Name("A Name")]
public class A
{
}
[Name("B Name")]
public class B
{
}
[Name("C Name")]
public class C
{
}
}
In order to share some static member between classes you need to inherit from base class which will contain static member:
public class Base
{
public static string MyName() { return "Bob"; }
}
public class A : Base
{
}
public class B : Base
{
}
You can't do what you are trying in your foreach loop, because variable t has type Type and Type do not have any MyName properties. You should use reflection to get MyName value:
Console.WriteLine(A.MyName()); // Bob
Console.WriteLine(B.MyName()); // Bob
foreach(var type in new[] { typeof(A), typeof(B) })
{
var flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy;
var method = type.GetMethod("MyName", flags);
Console.WriteLine(method.Invoke(null, null));
}
This code prints Bob for both types.

How to sort properties on a class using custom property attributes

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;
}

Get collection property of a specific type

I have a class MyDatabaseContext that has a series of DbSet collection properties:
public DbSet<EntityA> EntitiesA { get; set; }
public DbSet<EntityB> EntitiesB { get; set; }
public DbSet<EntityC> EntitiesC { get; set; }
I need to get the name of the collection given the type of the entity.
For example, I have "EntityB" and want to get as a result "EntitiesB".
I really wanted to avoid switch-case statements, since MyDatabaseContext is generated automatically (T4 templates).
if you just want the name of the property here you go. I would just refine the answer given by hunter. You can use the same method with string as return type.
public string GetEntitiName<T>() where T : class
{
PropertyInfo propInfo = typeof(MyDatabaseContext).GetProperties().Where(p => p.PropertyType == typeof(DbSet<T>)).FirstOrDefault();
string propertyName = propInfo.Name; //The string has the property name ..
return propertyName;
}
I tried a sample similar to your situation. Try replacing List with DbSet.
class Program
{
public static void GetEntities<T>() where T : class
{
var info = typeof(TestClass1).GetProperties().Where(p => p.PropertyType == typeof(List<T>));
Console.WriteLine(info.FirstOrDefault().Name);
}
static void Main(string[] args)
{
GetEntities<int>();
Console.ReadLine();
}
}
public class TestClass1
{
public List<int> IntTest { get; set; }
public List<double> DoubleTest { get; set; }
public List<string> IStringTest { get; set; }
}
This sample works.
I know this is old page, But my answer maybe useful for other guys referring here. (like me)
I think you want to accessing EntitiesB to run a query on it, like EntitiesB.Where(a=>a.bla=="blabla"). If I'm right or another visitor of this page needs something like this, just easily use the following code:
using System.Data.Entity.Infrastructure;
using System.Data.Objects;
((IObjectContextAdapter)_dbContext).ObjectContext.CreateObjectSet<EntityB>()
Description:
_dbContext is Context class inherting from DbContext.
EntitiesB is DbSet<EntityB> defined in Context class.
Example:
Ilist result = ((IObjectContextAdapter)_dbContext).ObjectContext.CreateObjectSet<EntityB>().Where(b=>b.bla=="blabla").ToList();
Your generated file is a partial class, you could create a new file and declare a class with same name using the keyword partial, then make a method which will return the desired Collection...
I haven't actually done this myself, but it sounds like what you want to do is to use reflection to locate the property of type "DbSet" that has the appropriate generic type parameter. The following pseudo-C# should get you started:
foreach ( FieldInfo field in this.GetType() )
{
if ( field.FieldType.IsGenericType )
{
foreach ( Type param in field.FieldType.GetGenericArguments() )
{
if ( param.Name == soughtType )
{
return field.Name;
}
}
}
}

Accessing C# property name or attributes

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).

Categories