Accessing the attribute of a generic parameter - c#

How can I access the attribute of a generic parameter? My code fails to get the attribute:
[AttributeUsage(AttributeTargets.GenericParameter)]
class MyAttribute : Attribute
{
public string name;
}
class A<[MyAttribute(name = "Genric")] Type>
{
public static void f()
{
MyAttribute w = Attribute.GetCustomAttributes(typeof(Type))[0] as MyAttribute; // fails
Console.WriteLine(w?.name);
}
}

The attribute you are looking for is related to A<> not Type. So you have to go from there. Have a look at this example:
using System;
public class Program
{
public static void Main()
{
var genericArguments = typeof(A<>).GetGenericArguments();
var attributes = Attribute.GetCustomAttributes(genericArguments[0]);
Console.WriteLine((attributes[0] as MyAttribute).Name);
}
}
[AttributeUsage(AttributeTargets.GenericParameter)]
class MyAttribute : Attribute
{
public string Name;
}
class A<[MyAttribute(Name = "MyAttributeValue")] Type>
{
}
The output is
MyAttributeValue

The attribute is applied to the generic argument, not the type itself, so your current approach wont work.
Try this instead:
MyAttribute w = typeof(A<>)
.GetGenericArguments()
.Select(t => t.GetCustomAttribute<MyAttribute>())
.SingleOrDefault();

Related

How can I know if some method has called that has a specific attribute in c#

class SampleClass
{
[SampleAttribute]
public void SampleMethod()
{
}
}
If there is a method like the above code. How can I know the method has called that has a specific attribute(In this case the attribute is 'SampleAttribute')? I know how to find methods that have specific attributes. But I don't know how to figure out when the method has called that has a specific attribute
You can do it in a few ways. But first, let's add some value to the SampleAttribute, to be sure, that everything is working:
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
public class SampleAttribute : Attribute
{
public SampleAttribute(string text)
{
Text = text;
}
public string Text { get; private set; }
}
And specify the attribute value to the method:
public class SampleClass
{
[SampleAttribute("This is attribute text")]
public void SampleMethod() { }
}
Now, using the reflection mechanism, we can extract the attribute value from the object:
var sampleClass = new SampleClass();
ExtractSampleAttributeValue(sampleClass);
private static string ExtractSampleAttributeValue(SampleClass sampleClass)
{
var methods = sampleClass.GetType().GetMethods();
var sampleMethod = methods.FirstOrDefault(method => method.Name == nameof(sampleClass.SampleMethod));
var sampleAttribute = Attribute.GetCustomAttribute(sampleMethod, typeof(SampleAttribute)) as SampleAttribute;
return sampleAttribute.Text;
}
Or even pass the method as the parameter:
var sampleClass = new SampleClass();
ExtractSampleAttributeValue(sampleClass.SampleMethod);
private static string ExtractSampleAttributeValue(Action sampleMethod)
{
var sampleAttribute = Attribute.GetCustomAttribute(sampleMethod.Method, typeof(SampleAttribute)) as SampleAttribute;
return sampleAttribute.Text;
}

Get DataContract Name property

I have a class that I have applied a DataContract attribute with a name property.
[DataContract(Name ="ProductInformation")]
public class ProductViewModel : BaseViewModel
{
[DataMember]
public string ProductName {get; set;}
}
All of my other ViewModel classes also inheriting from the BaseViewModel class.How do I retrieve the Name property from the BaseViewModel.
Update
If i understand you correctly, you want the most derived attribute when called form the base class. Note typeof(T) gets the instantiated type, I.e the most derived type
Also note GetTypeInfo() is basically added because this is a Xamarin Question
public static List<DataContractAttribute> GetDataContracts<T>()where T : class
{
return typeof(T).GetTypeInfo()
.GetCustomAttributes(false)
.OfType<DataContractAttribute>()
.ToList();
}
Original
public static List<DataContractAttribute> GetDataContracts<T>()where T : class
{
return typeof(T).BaseType?
.GetCustomAttributes(false)
.OfType<DataContractAttribute>()
.ToList();
}
public static void Main()
{
var attribute = GetDataContracts<ProductViewModel>().FirstOrDefault();
Console.WriteLine(attribute?.Name ?? "NoCigar");
}
PCL BaseViewModel Code
public class BaseViewModel
{
public static Dictionary<Assembly, Type> AllAssembelyUsedInBaseViewModel = new Dictionary<Assembly, Type>();
public static void RegisterAssemblyAndBase(Assembly assembly, Type baseType)
{
AllAssembelyUsedInBaseViewModel.Add(assembly, baseType);
}
static BaseViewModel()
{
RegisterAssemblyAndBase(typeof(BaseViewModel).GetTypeInfo().Assembly, typeof(BaseViewModel));
}
public static void GetDataContractNameFromAllAssembly()
{
List<string> dname = new List<string>();
foreach (var item in BaseViewModel.AllAssembelyUsedInBaseViewModel)
{
var assembly = item.Key;
var types = assembly.DefinedTypes.Where(x => x.BaseType == item.Value);
foreach (var type in types)
{
var attributes = type.GetCustomAttributes(typeof(DataContractAttribute), false);
var dt = attributes.FirstOrDefault() as DataContractAttribute;
if (dt != null)
{
dname.Add(dt.Name);
}
}
}
}
}
Register other UI Assembelies
public MainWindow()
{
InitializeComponent();
BaseViewModel.RegisterAssemblyAndBase(typeof(MainWindow).Assembly, typeof(BaseViewModel));
}
Get All Datacontract Name by calling
BaseViewModel.GetDataContractNameFromAllAssembly();

Attribute contents extracion

I'm trying to simplify code for extracting data from property attribute.
Attribute:
[AttributeUsage(AttributeTargets.Property)]
class NameAttribute : Attribute
{
public string Name { get; }
public ColumnAttribute(string name)
{
Name = name;
}
}
Attribute contents extraction code ( null-checks removed ):
public static string GetName<T>(string propName)
{
var propertyInfo = typeof(T).GetProperty(propName);
var nameAttribute = (NameAttribute)propertyInfo.GetCustomAttributes(typeof(NameAttribute)).FirstOrDefault();
return nameAttribute.Name;
}
Sample class:
class TestClass
{
[Column("SomeName")]
public object NamedProperty { get; set; }
}
Call sample:
var name = GetName<TestClass>(nameof(TestClass.NamedProperty))
Is it any way to rewrite attribute contents extraction method to simplify/shorten its call. It's too inconvenient for me due to its length.
Something like CallerMemberNameAttribute would be great but i found nothing.
Your syntax is already pretty short. The only redundant information is the class name, everything else is needed, it won't get much shorter. You could have a shorter syntax n your call as demonstrated below, where you remove the redundancy of the class name. However, that comes at the cost or a more complex implementation. It's up to you to decide if that's worth it:
namespace ConsoleApp2
{
using System;
using System.Linq.Expressions;
using System.Reflection;
static class Program
{
// your old method:
public static string GetName<T>(string propName)
{
var propertyInfo = typeof(T).GetProperty(propName);
var nameAttribute = propertyInfo.GetCustomAttribute(typeof(NameAttribute)) as NameAttribute;
return nameAttribute.Name;
}
// new syntax method. Still calls your old method under the hood.
public static string GetName<TClass, TProperty>(Expression<Func<TClass, TProperty>> action)
{
MemberExpression expression = action.Body as MemberExpression;
return GetName<TClass>(expression.Member.Name);
}
static void Main()
{
// you had to type "TestClass" twice
var name = GetName<TestClass>(nameof(TestClass.NamedProperty));
// slightly less intuitive, but no redundant information anymore
var name2 = GetName((TestClass x) => x.NamedProperty);
Console.WriteLine(name);
Console.WriteLine(name2);
Console.ReadLine();
}
}
[AttributeUsage(AttributeTargets.Property)]
class NameAttribute : Attribute
{
public string Name { get; }
public NameAttribute(string name)
{
this.Name = name;
}
}
class TestClass
{
[Name("SomeName")]
public object NamedProperty { get; set; }
}
}
The output is the same:
SomeName
SomeName

How to get type of custom class from string c#

I am trying to use GetType method for my custom class . I have the name of the class as string and i want to get type of it dynamically. I have the same name for two different classes which are located in different directories.
For Example:
MyClass.cs in Folder1:
namespace ConsoleApplication1.Folder1
{
public class MyClass : IClass
{
public void PrintMe()
{
System.Console.WriteLine("I am Folder 1 Class");
}
}
}
MyClass.cs in Folder2:
namespace ConsoleApplication1.Folder2
{
public class MyClass : IClass
{
public void PrintMe()
{
System.Console.WriteLine("I am Folder 2 Class");
}
}
}
Namespace is ConsoleApplication1
different classes with the same name are in the Folder1 and Folder2.
I want to get it's type from such a string:
var runtimeString = "Folder1.MyClass"
There is method mentioned in MSDN named GetType(string fileName)
How can i get type of the file and resolve it from the serviceLocator with type on runtime like:
var typeOfMyClass = GetType(runtimeString);
var instanceOfMyClass = ServiceLocator.Resolve<TypeOfMyClass>();
You appear to be describing a need for a factory method, something along the lines of:
public class MyClassFactory : IMyClassFactory
{
private Dictionary<string, Action<IClass>> _factory =
new Dictionary<string, Action<IClass>>
{
["Folder1.MyClass"] = () => new ConsoleApplication1.Folder1.MyClass(),
["Folder2.MyClass"] = () => new ConsoleApplication1.Folder2.MyClass(),
...
};
public IClass GetClassInstance(string myClassName)
{
if (_factory.Contains(myClassName))
{
return _factory[myClassName]();
}
throw NoSuchClassException(myClassName);
}
}
I believe the following is what you are trying to accomplish:
static void Main(string[] args)
{
var runtimeString = "Folder1.MyClass";
IClass instanceOfMyClass = (IClass)CreateInstance(runtimeString);
instanceOfMyClass.PrintMe();
Console.ReadKey();
}
private static object CreateInstance(string className)
{
var type = Assembly.GetExecutingAssembly().GetTypes()
.First(t => t.FullName.EndsWith(className));
return Activator.CreateInstance(type);
}
You may use Activator.CreateInstance() method to create an object of a class from its name string as below.
Create the Type object:
Type type1 = typeof(MyClass);
or
Type type1 = Type.GetType("MyClass");
Create an instance of that type:
Object o = Activator.CreateInstance(type1);

Attribute.IsDefined doesn't see attributes applied with MetadataType class

If I apply attributes to a partial class via the MetadataType attribute, those attributes are not found via Attribute.IsDefined(). Anyone know why, or what I'm doing wrong?
Below is a test project I created for this, but I'm really trying to apply custom attributes to a LINQ to SQL entity class - like this answer in this question.
Thanks!
using System;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace MetaDataTest
{
class Program
{
static void Main(string[] args)
{
PropertyInfo[] properties = typeof(MyTestClass).GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute)));
Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true));
Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length);
// Displays:
// False
// False
// 0
}
Console.ReadLine();
}
}
[MetadataType(typeof(MyMeta))]
public partial class MyTestClass
{
public string MyField { get; set; }
}
public class MyMeta
{
[MyAttribute()]
public string MyField { get; set; }
}
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : System.Attribute
{
}
}
The MetadataType attribute is used to specify help specify the additional information on the data object. To access the additional attributes you would need to do something like the following:
using System;
using System.Linq;
using System.ComponentModel.DataAnnotations;
using System.Reflection;
namespace MetaDataTest
{
class Program
{
static void Main(string[] args)
{
MetadataTypeAttribute[] metadataTypes = typeof(MyTestClass).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault();
if (metadata != null)
{
PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
Console.WriteLine(Attribute.IsDefined(propertyInfo, typeof(MyAttribute)));
Console.WriteLine(propertyInfo.IsDefined(typeof(MyAttribute), true));
Console.WriteLine(propertyInfo.GetCustomAttributes(true).Length);
RequiredAttribute attrib = (RequiredAttribute)propertyInfo.GetCustomAttributes(typeof(RequiredAttribute), true)[0];
Console.WriteLine(attrib.ErrorMessage);
}
// Results:
// True
// True
// 2
// MyField is Required
}
Console.ReadLine();
}
}
[MetadataType(typeof(MyMeta))]
public partial class MyTestClass
{
public string MyField { get; set; }
}
public class MyMeta
{
[MyAttribute()]
[Required(ErrorMessage="MyField is Required")]
public string MyField { get; set; }
}
[AttributeUsage(AttributeTargets.All)]
public class MyAttribute : System.Attribute
{
}
}
This also includes a sample attribute to show how to extract info that was added.
I had a similar situation. I ended up writing the following extension method for it.
The idea is to hide the abstraction of looking in 2 places (main class and metadata class).
static public Tattr GetSingleAttribute<Tattr>(this PropertyInfo pi, bool Inherit = true) where Tattr : Attribute
{
var attrs = pi.GetCustomAttributes(typeof(Tattr), Inherit);
if (attrs.Length > 0)
return (Tattr)attrs[0];
var mt = pi.DeclaringType.GetSingleAttribute<MetadataTypeAttribute>();
if (mt != null)
{
var pi2 = mt.MetadataClassType.GetProperty(pi.Name);
if (pi2 != null)
return pi2.GetSingleAttribute<Tattr>(Inherit);
}
return null;
}
My solution for generic use. Get the attribute the property that you are looking for. Return null if not found.
If found, it returns the attribute itself. So you can have access to the properties inside the attribute if you wihs.
Hopes this help.
public static Attribute GetAttribute<T>(this PropertyInfo PI, T t) where T: Type
{
var Attrs = PI.DeclaringType.GetCustomAttributes(typeof(MetadataTypeAttribute), true);
if (Attrs.Length < 1) return null;
var metaAttr = Attrs[0] as MetadataTypeAttribute;
var metaProp = metaAttr.MetadataClassType.GetProperty(PI.Name);
if (metaProp == null) return null;
Attrs = metaProp.GetCustomAttributes(t, true);
if (Attrs.Length < 1) return null;
return Attrs[0] as Attribute;
}
Given the following classes:
public partial class Person
{
public int PersonId { get; set; }
}
[MetadataType(typeof(PersonMetadata))]
public partial class Person
{
public partial class PersonMetadata
{
[Key]
public int PersonId { get; set; }
}
}
I needed to get see if Key has been defined on a property for Person class. I then needed to get the value of the property. Using #AdamGrid answer, I modified the code like this to get it:
private static object GetPrimaryKeyValue(TEntity entity)
{
MetadataTypeAttribute[] metadataTypes = typeof(TEntity).GetCustomAttributes(typeof(MetadataTypeAttribute), true).OfType<MetadataTypeAttribute>().ToArray();
MetadataTypeAttribute metadata = metadataTypes.FirstOrDefault();
if (metadata == null)
{
ThrowNotFound();
}
PropertyInfo[] properties = metadata.MetadataClassType.GetProperties();
PropertyInfo primaryKeyProperty =
properties.SingleOrDefault(x => Attribute.GetCustomAttribute(x, typeof(KeyAttribute)) as KeyAttribute != null);
if (primaryKeyProperty == null)
{
ThrowNotFound();
}
object primaryKeyValue = typeof(TEntity).GetProperties().Single(x => x.Name == primaryKeyProperty.Name).GetValue(entity);
return primaryKeyValue;
}
private static void ThrowNotFound()
{
throw new InvalidOperationException
($"The type {typeof(TEntity)} does not have a property with attribute KeyAttribute to indicate the primary key. You must add that attribute to one property of the class.");
}

Categories

Resources