Get custom attribute from specific object property/field - c#

I've been searching for a while now and tested several methods, but i didn't find the answer i was looking for. I'll try to explain.
I have an object with several fields/properties. These properties have custom attributes.
What i want is to get the custom attribute from a specific propertie without all the knowlege of the object.
The are the base classes
// FieldAttr has a public Text propery
public class TestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1
{
public string Value { get; set; }
}
public class FLDtype2
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public EntityFieldType(string txt)
{
this._text = txt;
}
public string Text { get { return this._text; } }
}
And i want to be able to do this in my application:
static void Main(string[] args)
{
TestObject test = new TestObject();
// (Option 1: preferred)
Console.WriteLine(test.testfld1.getFieldAttr().Text);
// (Option 2)
Console.WriteLine(test.getFieldAttr(test.testfld1).Text);
}
Is this possible? I've seen methods to get custom attribute values from all properties/fields of an object, but not for a specific field.
I've got a working method to get custom attribute from an enum, but wasn't able to recreate it for object fields/properties. This is because i couldn't get the name of the field i was trying to explore, because (for example) test.testfld1.ToString() give's me "ns.FLDtype1".
Looking forward for the answer :)
(and excuse my english)

Yes it is possible:
public static class Extensions
{
public static FieldAttr GetFieldAttr(
this TestObject source,
Expression<Func<TestObject,object>> field)
{
var member = field.Body as MemberExpression;
if (member == null) return null; // or throw exception
var fieldName = member.Member.Name;
var test = typeof (TestObject);
var fieldType = test.GetField(fieldName);
if (fieldType != null)
{
var attribute = fieldType.GetCustomAttribute<FieldAttr>();
return attribute;
}
return null;
}
}
Usage:
TestObject test = new TestObject();
var attr = test.GetFieldAttr(x => x.testfld3);
if(attr != null) Console.WriteLine(attr.Text);
Here is the fiddle

After another day of trial and error I decided to make use of Selman22 answer with a little modification. This is code I created:
public class TestObject : iTestObject
{
// Declare fields
[FieldAttr("prop_testfld1")]
public FLDtype1 testfld1 = new FLDtype1();
[FieldAttr("prop_testfld2")]
public FLDtype2 testfld2 = new FLDtype2();
[FieldAttr("prop_testfld3")]
public FLDtype1 testfld3;
}
public class FLDtype1 : iField
{
public string Value { get; set; }
}
public class FLDtype2 : iField
{
public Guid Value { get; set; }
}
public sealed class FieldAttr: System.Attribute
{
private string _txt;
public FieldAttr(string txt)
{
this._txt = txt;
}
public string Text { get { return this._txt; } }
}
public interface iField { }
public interface iTestObject { }
public static class Extensions
{
public static FieldAttr GetFieldAttr<T>(this T source, Expression<Func<iField>> field) where T : iTestObject
{
// Get member body. If no body present, return null
MemberExpression member = (MemberExpression)field.Body;
if (member == null) { return null; }
// Get field info. If no field info present, return null
FieldInfo fieldType = typeof(T).GetField(member.Member.Name);
if (fieldType == null) { return null; }
// Return custom attribute
return fieldType.GetCustomAttribute<FieldAttr>();
}
}
Usage:
public class Program
{
public static void Main()
{
TestObject test = new TestObject();
Console.WriteLine(test.GetFieldAttr(() => test.testfld1).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld2).Text);
Console.WriteLine(test.GetFieldAttr(() => test.testfld3).Text);
}
}
Uses:
using System;
using System.Linq;
using System.Reflection;
using System.Linq.Expressions;
I have implemented interfaces to protect the GetFieldAttr method
#Sulman22: Thnx for the response!

Related

How to get a specific constructor that matches an Interface?

So playing with my own test Dependency Injector class. (yeah tons out there but this is just for fun)
Works decent but I don't know how to get the correct constructor based on the Interface passed in.
internal class DiContainer
{
private readonly Dictionary<Type, RegistryRecord> registry = new Dictionary<Type, RegistryRecord>();
private static DiContainer instance;
private DiContainer()
{
}
public static DiContainer GetInstance()
{
return instance ??= new DiContainer();
}
public void Register<T, C>() where C : class, T
{
registry.Add(typeof(T), new RegistryRecord
{
InterfaceType = typeof(T),
ConcreteType = typeof(C),
IsSingleTon = false
});
}
public void Register<C>() where C : class
{
Register(typeof(C));
}
public void Register(Type t)
{
registry.Add(t, new RegistryRecord
{
InterfaceType = t,
ConcreteType = t,
IsSingleTon = false
});
}
public void RegisterSingleton<T, C>(C instance = null) where C : class, T
{
registry.Add(typeof(T), new RegistryRecord
{
InterfaceType = typeof(T),
ConcreteType = typeof(C),
IsSingleTon = true,
Instance = instance
});
}
public T Get<T>()
{
return (T) Get(typeof(T));
}
public object Get(Type t)
{
ConstructorInfo constructor;
RegistryRecord r = null;
if (t.IsInterface && registry.ContainsKey(t))
{
r = registry[t];
if (r.IsSingleTon && r.Instance != null) return r.Instance;
constructor = r.ConcreteType.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
}
else
{
//todo how do we select the correct constructor?
constructor = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
}
var parameters = constructor.GetParameters();
//recurse to build dependency chain
var objects = parameters.Select(parameter => Get(parameter.ParameterType)).ToList();
var obj = constructor.Invoke(objects.ToArray());
if (r != null && r.IsSingleTon)
{
r.Instance = obj;
}
return obj;
}
}
internal class RegistryRecord
{
public Type InterfaceType { get; set; }
public Type ConcreteType { get; set; }
public object Instance { get; set; }
public bool IsSingleTon { get; set; }
}
So the problem is
constructor = t.GetConstructors(BindingFlags.Instance | BindingFlags.Public)[0];
I am just assuming the first constructor which is awful. But I have the definition of the interface I could be using.
How do I get the parameters of my interface and check them against the constructor?
Would like to select a constructor that matches the interface, or at least partially matches optimally.
edit
An example
using System;
namespace DITest
{
internal class Program
{
private static void Main(string[] args)
{
var di = DiContainer.GetInstance();
//Register classes / interfaces
di.Register<IPhoneResolver, PhoneResolver>();
di.Register<Customer>();
//Get class where dependency should be injected
var x = di.Get<Customer>();
Console.WriteLine(x.resolver.Name);
Console.Read();
}
}
public class Customer
{
//Remove this and everything is ok. Because we select the first one not the right one
public Customer()
{
}
public Customer(IPhoneResolver resolver)
{
this.resolver = resolver;
}
public IPhoneResolver resolver { get; set; }
}
public interface IPhoneResolver
{
string Name { get; set; }
bool DoesSomething();
}
public class PhoneResolver : IPhoneResolver
{
public string Name { get; set; } = "test";
public bool DoesSomething()
{
return true;
}
}
}
So because the first constructor is null there is an issue.
I need a way to resolve the correct constructor. I have the interface via the RegistryRecord and (type) InterfaceType. I need to find a way to get a constructor that matches that types parameters.

Handling generic properties via reflection

If I have the following wrapper class:
public class Wrapper<T>
{
public T Data { get; set; }
public string[] Metadata { get;set;
}
and another class then exposes that value without generics:
public class SomeOtherClass
{
public object WrappedData { get;set };
}
, how can I get at the original unwrapped data?
I can test for it, using something like:
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic originalValue = someOtherClass.WrappedData;
}
but I can't then call the .Data property on originalValue, getting a RuntimeBinderException.
Update
A little more context might help. I am working on a WebAPI where I am wanting to implement HATEOAS. So my wrapper class is containing the data that will be returned plus metadata, and I am writing an action filter that will unwrap the data, returning it in the response body, and put the metadata into response headers. The action filter is currently implemented as follows:
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
if (actionExecutedContext.Request.Method == HttpMethod.Get)
{
var objectContent = actionExecutedContext.Response.Content as ObjectContent;
if (objectContent != null)
{
var type = objectContent.ObjectType;
var formatter = actionExecutedContext
.ActionContext
.ControllerContext
.Configuration
.Formatters
.First(f => f.SupportedMediaTypes
.Contains(new MediaTypeHeaderValue(actionExecutedContext
.Response
.Content
.Headers
.ContentType
.MediaType)));
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic value = objectContent.Value;
actionExecutedContext.Response.Content = new ObjectContent(value.Data.GetType(), value.Data, formatter);
}
}
}
base.OnActionExecuted(actionExecutedContext);
}
Obviously not all my API endpoints currently wrap their data, so if the response is not returning a Wrapper<T> instance, I want to exit the action filter without modifying the response. If it is, then pull out the value of .Data and rewrite the response body with it.
It's not clear from the posted code what objectContent.ObjectType is, so I would modify the code to check the actual value:
object value = objectContent.Value;
if (value != null && value.GetType().IsGenericType && value.GetType().GetGenericTypeDefinition() == typeof(Wrapper<>))
{
object data = ((dynamic)value).Data;
actionExecutedContext.Response.Content = new ObjectContent(data.GetType(), data, formatter);
}
But you can avoid reflection and dynamic calls and make your life much easier if you backup your generic class with a non generic interface. For instance
public interface IWrapper
{
object Data { get; }
string[] Metadata { get; }
}
public class Wrapper<T> : IWrapper
{
public T Data { get; set; }
object IWrapper.Data { get { return Data; } }
public string[] Metadata { get; set; }
}
Then you can do simple
var wrapper = objectContent.Value as IWrapper;
if (wrapper != null)
{
actionExecutedContext.Response.Content = new ObjectContent(wrapper.Data.GetType(), wrapper.Data, formatter);
}
The following code works:
using System;
namespace ConsoleApplication1
{
class Program
{
public class Wrapper<T>
{
public T Data { get; set; }
public string[] Metadata
{
get; set;
}
}
public class SomeOtherClass
{
public object WrappedData { get; set; }
}
static void Main(string[] args)
{
var wrappedData = new Wrapper<int> { Data = 3 };
var someObject = new SomeOtherClass { WrappedData = wrappedData };
dynamic d = someObject.WrappedData;
Console.WriteLine(d.Data);
}
}
}
So, It isn't clear what your problem is!
Would it help if you added the type to your wrapper?
public class Wrapper<T>
{
public Type MyType{get;set;}
public T Data { get; set; }
public string[] Metadata { get;set;}
public Wrapper(T data){
MyType = data.GetType();
Data = data;
}
}
Unclear exactly what you are trying to do:
object obj = new Wrapper<SomeOtherClass> { Data = new SomeOtherClass { WrappedData = "Hello" } };
Type type = obj.GetType();
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Wrapper<>))
{
dynamic data = ((dynamic)obj).Data;
dynamic wrappedData = data.WrappedData;
}
Note that there is no guarantee that there is a WrappedData property inside the Data property: WrappedData is a property of SomeOtherClass, but for example obj could be:
object obj = new Wrapper<string> { Data = "Hello" };

How to trigger a Generic Class method recursively changing the type of T?

I've created a Generic Class to parse some data into another instance of a class (MyClass1). Since MyClass1 has only built-in C# types, my GenericMethod works fine. The problem starts to grow when MyClass1 has another MyClass2 property and I still want to invoke my GenericMethod to parse my data.
I can't trigger my Generic Class method inside its scope since I need to change the type of T. Is there any way to solve this problem?
public class MyClass1
{
public int MyIntProperty { get; set; }
public string MyStringProperty { get; set; }
public MyClass2 MyClass2Property { get; set; }
}
public class MyClass2
{
public int MyOtherIntProperty { get; set; }
public string MyOtherStringProperty { get; set; }
public bool MyOtherBoolProperty { get; set; }
}
public class MyGenericClass<T> where T : class
{
public static T MyGenericMethod()
{
T o = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] pi = typeof(T).GetProperties();
for(int i = 0; i < pi.Count(); i++)
{
if(pi[i].Name == "MyClass2Property")
{
//How to proceed ?
MyGenericClass<???>.MyGenericMethod();
}
else
{
pi[i].SetValue(o, Convert.ChangeType(someValue, pi[i].PropertyType), null);
}
}
}
}
public static void Main(string[] args)
{
MyClass1 mc1 = MyGenericClass<MyClass1>.MyGenericMethod();
//Do something with mc1
}
You can look at this post
and maybe try something like this
public static class MyGenericClass<T> where T : class
{
public static T MyGenericMethod()
{
T o = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] pi = typeof(T).GetProperties();
for(int i = 0; i < pi.Count(); i++)
{
if(pi[i].Name == "MyClass2Property")
{
//How to proceed ?
Type t = typeof (MyGenericClass<>);
Type genericType = t.MakeGenericType(new System.Type[] { pi[i].PropertyType });
var c = Activator.CreateInstance(genericType);
dynamic mgm = Convert.ChangeType(c, genericType);
mgm.MyGenericMethod();
}
else
{
pi[i].SetValue(o, Convert.ChangeType(someValue, pi[i].PropertyType), null);
}
}
}
Depending on your needs, you could also define some additional meta information about the property indicating what you would like to do with it if found.
Building on others' comments and answers, here is what I came up with including an attribute decoration that allows you to dynamically build objects and has the following enhancements:
Properties can be named anything you want
No need for if statements as new properties are added.
No need for the MyGenericMethod method to ever change.
Additional meta-information can be added to the custom attribute to add further customization in the future.
Objects can be nested as deeply as needed.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Dynamic;
public class MyClass1 {
public int MyIntProperty { get; set; }
public string MyStringProperty { get; set; }
[MyCustom()]
public MyClass2 MyClass2Property { get; set; }
}
public class MyClass2 {
public int MyOtherIntProperty { get; set; }
public string MyOtherStringProperty { get { return "oooh, fancy"; } set {} }
public bool MyOtherBoolProperty { get; set; }
}
public static class MyGenericClass<T> where T : class {
public static T MyGenericMethod() {
T o = (T)Activator.CreateInstance(typeof(T));
PropertyInfo[] pi = typeof(T).GetProperties();
for (int i = 0; i < pi.Count(); i++) {
if (pi[i].GetCustomAttributes(true).Any() && pi[i].GetCustomAttributes(true).Where((x) => x is MyCustomAttribute).Any()) {
//How to proceed ?
var c = Activator.CreateInstance(pi[i].PropertyType);
Type t = typeof(MyGenericClass<>);
Type genericType = t.MakeGenericType(new System.Type[] { pi[i].PropertyType });
MethodInfo m = genericType.GetMethod(MethodInfo.GetCurrentMethod().Name);
c = m.Invoke(null, null);
pi[i].SetValue(o, c, null);
} else {
//Normal property assignment.
}
}
return o;
}
}
public class Program {
public static void Main(string[] args) {
MyClass1 mc1 = MyGenericClass<MyClass1>.MyGenericMethod();
//Do something with mc1
Console.WriteLine(mc1.MyClass2Property.MyOtherStringProperty);
Console.ReadLine();
}
}
[AttributeUsage(AttributeTargets.Property, AllowMultiple=false)]
public class MyCustomAttribute : Attribute {
}
I tweaked this so it can be run as is.
Edit:
I also changed the code to invoke the method being called on itself to avoid a "magic string".

How to determine if a customAttribute from a class is equals to another?

check that I have a customAttribute called ResponseAttributes. I have declared an interface and several concrete classes { Question 1, Question2, Question3 }
[AttributeUsage(AttributeTargets.Property)]
public class ResponseAttribute : Attribute { }
public interface IQuestion { }
public class Question1 : IQuestion
{
[Response]
public string Response { get; set; }
public Question1() { Response = "2+1"; }
}
public class Question2 : IQuestion
{
[Response]
public decimal Response { get; set; }
public Question2() { Response = 5; }
}
public class Question3 : IQuestion
{
[Response]
public string Response { get; set; }
public Question3() { Response = "2+1"; }
}
Now, what I'm trying to do is how to verify a class which contains that attribute is equals to another?
I mean:
List<IQuestion> questions = new List<IQuestion>()
{
new Question1(), new Question2()
};
Question3 question3 = new Question3();
foreach (var question in questions)
{
// how to verify this condition:
// if (customAttribute from question3 is equals to customAttribute fromquestion)
// of course the question3 is equals to 1
}
As you can, they are different types, that's the reason why I set as ResponseAttribute.
you could try using an interface, with Resposnse property (type object)
if you can not, you could use a class-level attribute that tell you the "Response property" than, you can use reflection on that property
Example:
public class ResponseAttribute : Attribute {
public string PropertyName { get; set }
}
[ResponseAttribute ("CustomResponse")}
public class Question1 {
public string CustomResponse;
}
via reflection
foreach(var question in questions) {
var responseAttr = (ResponseAttribute) question.GetType().GetCustomAttributes(typeof(ResponseAttribute));
var questionResponse= question.GetType().GetProperty(responseAttr.PropertyName,question,null);
}
try overriding equals method:
public override bool Equals(object obj)
{
if (obj is IQuestion)
return this.Response == ((IQuestion)obj).Response;
else
return base.Equals(obj);
}
hope this helps

Accessing object properties from string representations

In actionscript an object's property can be accesses in this way:
object["propertyname"]
Is something like this possible in c#, without using reflection?
No, you have to use reflection.
If could at most create an helper extension method like in this example:
using System;
static class Utils {
public static T GetProperty<T>(this object obj, string name) {
var property = obj.GetType().GetProperty(name);
if (null == property || !property.CanRead) {
throw new ArgumentException("Invalid property name");
}
return (T)property.GetGetMethod().Invoke(obj, new object[] { });
}
}
class X {
public string A { get; set; }
public int B { get; set; }
}
class Program {
static void Main(string[] args) {
X x = new X() { A = "test", B = 3 };
string a = x.GetProperty<string>("A");
int b = x.GetProperty<int>("B");
}
}
This is not good, however.
First because you are turning compile-time errors in runtime errors.
Second, the performance hit from reflection is unjustified in this case.
I think that the best advice here is that you should not try to program in C# as if it was ActionScript.
You can define indexer in your class:
public class IndexerTest
{
private Dicionary<string, string> keyValues = new ...
public string this[string key]
{
get { return keyValues[key]; }
set { keyValues[key] = value; }
}
}
And use it like this:
string property = indexerTest["propertyName"];

Categories