我正在开发一个将数据存储在 ConfigurationManager.AppSettings 文件中的应用程序,并且我希望以与现在不同的方式实现它。目前,我有一个接口(见下文),每个具有可保存特征的类都需要实现该接口,然后从我的 Config 类中调用静态保存方法(下面的示例)。我不喜欢我的 Config 类和具有可保存数据的类之间的耦合,因此我的理想是拥有一个指示应保存属性的属性。然后,我不会调用管理器类中的 SaveData 或 LoadData 函数,而是调用一个设置/保存所有属性的函数。这看起来与 [Serializeable] 在默认 C# 中的工作方式类似,所以我认为这是可能的。然而,我的大部分搜索都没有结果。关于如何实现这样的事情有什么想法吗?
界面
示例
反射就是您正在寻找的。
Reflection 提供描述程序集、模块和类型的对象(Type 类型)。您可以使用反射动态创建类型的实例、将类型绑定到现有对象,或者从现有对象获取类型并调用其方法或访问其字段和属性。如果您在代码中使用属性,反射使您能够访问它们。
假设您只对属性感兴趣,则可以使用
typeof
或 GetType
来获取 System.Type
的实例。然后您可以致电 GetProperties
获取 IEnumerable<PropertyInfo>
。 PropertyInfo
有一个 Attributes
属性,您可以使用它来检索该属性的属性。您还可以使用 PropertyInfo
的实例来检索属性的值。
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();
}
}
当然,这个例子只有
string
属性。您将必须找出某种方法来处理非字符串的属性;例如,您的示例中有一个 ObservableCollection
。
只是为了选择这样做,RepoDb 实现了 IPropertyHandler 接口。
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;
}
在你的课堂上
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
[PropertyHandler(typeof(PersonAddressPropertyHandler))]
public Address Address { get; set; }
}
一切都在文档中RepoDb