早上好。
我需要将几乎任何类型的可序列化对象序列化为*.INI 文件。
我正在尝试实现IFormatter
,其中void Serialize(Stream, object)
方法从对象实例获取属性信息,然后为原始类型或部分写入键/值+复杂类型的键/值。
将此代码作为要序列化的对象的示例。
[Serializable]
public class EmployeeList
{
#region Properties
public List<Employee> Employees { get; private set; }
public string Banana { get; set; }
#endregion
#region Constructors
public EmployeeList()
{
Employees = new List<Employee>();
}
#endregion
#region Public Methods
public void Serialize()
{
IFormatter formatter = new IniFormatter();
using (FileStream outputStream = File.Create("employees.ini"))
{
try
{
formatter.Serialize(outputStream, this);
}
catch (SerializationException ex)
{
//...
}
}
}
#endregion
}
[Serializable]
public class Employee
{
#region Properties
public string Name
{
get;
set;
}
public Gender Gender
{
get;
set;
}
public List<Role> Roles
{
get;
set;
}
#endregion
#region Constructors
public Employee()
{
}
#endregion
}
[Serializable]
public enum Gender
{
Male,
Female,
Other
}
[Serializable]
public class Role
{
public string Name
{
get;
set;
}
public int Value
{
get;
set;
}
#region Constructors
public Role()
{
}
#endregion
}
好吧,因为我试图通过反射来获取属性名称和值,所以一切似乎都是微不足道的;System.Reflection.TargetParameterCountException
当我试图反思时,我不断地得到一个List<Employee>
(见方法pi.GetValue(obj, null);
,在哪里pi
)PropertyInfo
。
这是我的代码IniFormatter
:
public class IniFormatter : IFormatter
{
#region Properties
public ISurrogateSelector SurrogateSelector { get; set; }
public SerializationBinder Binder { get; set; }
public StreamingContext Context { get; set; }
#endregion
#region Constructors
public IniFormatter()
{
Context = new StreamingContext(StreamingContextStates.All);
}
#endregion
#region IFormatter Members
public object Deserialize(Stream serializationStream)
{
throw new NotImplementedException();
}
public void Serialize(Stream serializationStream, object graph)
{
var propertyInfos = graph.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
StreamWriter sw = new StreamWriter(serializationStream);
foreach (var propertyInfo in propertyInfos)
{
if (!propertyInfo.CanRead)
{
continue;
}
if (Attribute.IsDefined(propertyInfo, typeof (NonSerializedAttribute)))
{
continue;
}
if (propertyInfo.PropertyType.IsPrimitive)
{
sw.WriteLine("{0}={1}", propertyInfo.Name, propertyInfo.GetValue(graph, null));
}
//object/complex types need to recursively call this method until the end of the tree is reached
else
{
var complexType = GetPropertyValue(graph, propertyInfo.Name);
Serialize(serializationStream, complexType);
}
}
sw.Close();
}
#endregion
public static object GetPropertyValue(object sourceObject, string propertyName)
{
if (sourceObject == null)
{
return null;
}
object obj = sourceObject;
// Split property name to parts (propertyName could be hierarchical, like obj.subobj.subobj.property
string[] propertyNameParts = propertyName.Split('.');
foreach (string propertyNamePart in propertyNameParts)
{
if (obj == null)
{
return null;
}
// propertyNamePart could contain reference to specific
// element (by index) inside a collection
if (!propertyNamePart.Contains("["))
{
PropertyInfo pi = obj.GetType().GetProperty(propertyNamePart, BindingFlags.Public | BindingFlags.Instance);
if (pi == null)
{
return null;
}
obj = pi.GetValue(obj, null);
}
else
{
// propertyNamePart is a reference to specific element
// (by index) inside a collection
// like AggregatedCollection[123]
// get collection name and element index
int indexStart = propertyNamePart.IndexOf("[") + 1;
string collectionPropertyName = propertyNamePart.Substring(0, indexStart - 1);
int collectionElementIndex = Int32.Parse(propertyNamePart.Substring(indexStart, propertyNamePart.Length - indexStart - 1));
// get collection object
PropertyInfo pi = obj.GetType().GetProperty(collectionPropertyName, BindingFlags.Public | BindingFlags.Instance);
if (pi == null)
{
return null;
}
object unknownCollection = pi.GetValue(obj, null);
// try to process the collection as array
if (unknownCollection.GetType().IsArray)
{
object[] collectionAsArray = unknownCollection as Array[];
obj = collectionAsArray[collectionElementIndex];
}
else
{
// try to process the collection as IList
IList collectionAsList = unknownCollection as IList;
if (collectionAsList != null)
{
obj = collectionAsList[collectionElementIndex];
}
else
{
// ??? Unsupported collection type
}
}
}
}
return obj;
}
}
我从控制台应用程序运行我的测试,这样做:
Employee employee = new Employee {Name = "Nando", Gender = Gender.Male, Roles = new List<Role> {new Role {Name = "CEO", Value = 1}}};
EmployeeList employeeList = new EmployeeList();
employeeList.Banana = "It's delicious!";
employeeList.Employees.Add(employee);
employeeList.Serialize();
我可以获得Banana
属性值(对不起,属性名称,当我生气时,我的命名约定会发疯),没有别的。
我知道,这是一个相当“解决我的问题”的问题,但我找不到可以理解的来源,我可以完全反映一个对象及其属性名称和值的处理。
所以我向熟练的开发人员寻求帮助,向我指出一些来源,我快疯了。:-) 非常感谢,
南多