Reputation: 21
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
Upvotes: 0
Views: 1358
Reputation: 111
Just for option to do it, RepoDb implements IPropertyHandler interface.
public class PersonAddressPropertyHandler : IPropertyHandler<string, Address>
{
public Address Get(string input, PropertyHandlerGetOptions options) =>
!string.IsNullOrEmpty(input) ? JsonConvert.Deserialize<Address>(input) : null;
public string Set(Address input, PropertyHandlerSetOptions options) =>
(input != null) ? JsonConvert.Serialize(input) : null;
}
And in your class
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[PropertyHandler(typeof(PersonAddressPropertyHandler))]
public Address Address { get; set; }
}
all is in doc RepoDb
Upvotes: 0
Reputation: 3539
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.
Upvotes: 2