简体   繁体   中英

Custom Attributes and Accessing Them In C#

I am working on an application that stores data in the ConfigurationManager.AppSettings file, and I am wanting to implement it in a different way than how I do right now. Currently, I have an interface (see below) that each class with saveable traits needs to implement, then call the static save methods from my Config class (example below). I don't like the coupling between my Config class and the class with the saveable data, so my ideal would be to have an attribute that indicates a property should be saved. Then, instead of calling the SaveData or LoadData functions in my manager class, I would call a function that sets/saves all the attributed properties. This seems similar to how [Serializeable] works in default C#, so I imagine it's possible somehow. However, most of my searches have been fruitless. Any ideas on how to implement something like this?

Interface

见接口

Example

例子

Reflection is what you're looking for.

Reflection provides objects (of type Type) that describe assemblies, modules, and types. You can use reflection to dynamically create an instance of a type, bind the type to an existing object, or get the type from an existing object and invoke its methods or access its fields and properties. If you are using attributes in your code, reflection enables you to access them.

Assuming that you're only interested in properties, you can use typeof or GetType to get an instance of System.Type . You can then call GetProperties to get an IEnumerable<PropertyInfo> . PropertyInfo has an Attributes property that you can use to retrieve the attributes for that property. You can also use an instance of PropertyInfo to retrieve the value of the property.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

[AttributeUsage(AttributeTargets.Property)]
public class MyAttribute : Attribute
{

}

public class Foo
{
   [My]
   public string Bar { get; set; }

   public string Baz { get; set; }

   [My]
   public string Id { get; set; }
}

public static class Utilities
{
   public static IEnumerable<PropertyInfo> GetPropertiesWithMyAttribute(object obj)
   {
      return obj.GetType()
         .GetProperties(BindingFlags.Instance | BindingFlags.Public)
         .Where(pi => pi.CustomAttributes.Any(ca => ca.AttributeType == typeof(MyAttribute)));
   }
}

class Program
{
   static void Main(string[] args)
   {
      var foo = new Foo()
      {
         Bar = "Bar_Value",
         Baz = "Baz_Value",
         Id = "Id_Value"
      };

      foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
      {
         Console.WriteLine($"{pi.Name}: {pi.GetMethod.Invoke(foo, null).ToString()}");
      }
      foreach (var pi in Utilities.GetPropertiesWithMyAttribute(foo))
      {
         pi.SetMethod.Invoke(foo, new object[] { $"{pi.Name}_Value_Reflection" });
      }
      Console.WriteLine(foo.Bar);
      Console.WriteLine(foo.Baz);
      Console.WriteLine(foo.Id);
      Console.ReadKey();
   }
}

Of course, this example only string properties. You're going to have to figure out some way to deal with properties that aren't strings; for example you haven an ObservableCollection in your example.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM