C# 属性和字段的强类型序列化的方法扩展

C# 属性和字段的强类型序列化的方法扩展,c#,serialization,reflection,C#,Serialization,Reflection,我试图创建一个用于序列化对象的实用函数, 通常,序列化将按如下方式进行: [Serializable] public CoolCat : ISerializable { public string Name; public void CoolCar(SerializationInfo info, StreamingContext context) { Name = (string)info.GetValue("Name", typeof(string))

我试图创建一个用于序列化对象的实用函数, 通常,序列化将按如下方式进行:

[Serializable]
public CoolCat : ISerializable
{
    public string Name;

    public void CoolCar(SerializationInfo info, StreamingContext context)
    {
        Name = (string)info.GetValue("Name", typeof(string));
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue("Name", Name);
    }
}
但是,我希望能够做到以下几点:

[Serializable]
public CoolCat : ISerializable
{
    public string Name;

    public void CoolCar(SerializationInfo info, StreamingContext context)
    {
        Name = info.GetValue<string>(() => Name);
    }

    public void GetObjectData(SerializationInfo info, StreamingContext context)
    {
        info.AddValue<string>(() => Name);
    }
}
[可序列化]
公共CoolCat:ISerializable
{
公共字符串名称;
公共空CoolCar(SerializationInfo信息、StreamingContext上下文)
{
Name=info.GetValue(()=>Name);
}
public void GetObjectData(SerializationInfo信息、StreamingContext上下文)
{
info.AddValue(()=>名称);
}
}
我使用以下两种方法来实现这一点:

此选项用于反序列化值:

public static T GetValue<T>(this SerializationInfo Source, Expression<Func<T>> MemberExpression)
{
    string Name = ((MemberExpression)MemberExpression.Body).Member.Name;
    return (T)Source.GetValue(Name, typeof(T));
}
public static void AddValue<T>(this SerializationInfo Source, Expression<Func<T>> MemberExpression)
{
    MemberExpression Body = MemberExpression.Body as MemberExpression;

    if (Body == null)
    {
        UnaryExpression UnaryBody = MemberExpression.Body as UnaryExpression;

        if (UnaryBody != null)
        {
            Body = UnaryBody.Operand as MemberExpression;
        }
        else
        {
            throw new ArgumentException("Expression is not a MemberExpression", "MemberExpression");
        }
    }

    string Name = Body.Member.Name;

    if (Body.Member is FieldInfo)
    {
        T Value = (T)((FieldInfo)Body.Member).GetValue(((ConstantExpression)Body.Expression).Value);
        Source.AddValue(Name, Value, typeof(T));
    }
    else if (Body.Member is PropertyInfo)
    {
        T Value = (T)((PropertyInfo)Body.Member).GetValue(((ConstantExpression)Body.Expression, null);
        Source.AddValue(Name, Value, typeof(T));
    }
    else
    {
        throw new ArgumentException("Expression must refer to only a Field or a Property", "MemberExpression");
    }
}
public static T GetValue(此SerializationInfo源,表达式MemberExpression)
{
字符串名称=((MemberExpression)MemberExpression.Body).Member.Name;
return(T)Source.GetValue(Name,typeof(T));
}
这个用于序列化值:

public static T GetValue<T>(this SerializationInfo Source, Expression<Func<T>> MemberExpression)
{
    string Name = ((MemberExpression)MemberExpression.Body).Member.Name;
    return (T)Source.GetValue(Name, typeof(T));
}
public static void AddValue<T>(this SerializationInfo Source, Expression<Func<T>> MemberExpression)
{
    MemberExpression Body = MemberExpression.Body as MemberExpression;

    if (Body == null)
    {
        UnaryExpression UnaryBody = MemberExpression.Body as UnaryExpression;

        if (UnaryBody != null)
        {
            Body = UnaryBody.Operand as MemberExpression;
        }
        else
        {
            throw new ArgumentException("Expression is not a MemberExpression", "MemberExpression");
        }
    }

    string Name = Body.Member.Name;

    if (Body.Member is FieldInfo)
    {
        T Value = (T)((FieldInfo)Body.Member).GetValue(((ConstantExpression)Body.Expression).Value);
        Source.AddValue(Name, Value, typeof(T));
    }
    else if (Body.Member is PropertyInfo)
    {
        T Value = (T)((PropertyInfo)Body.Member).GetValue(((ConstantExpression)Body.Expression, null);
        Source.AddValue(Name, Value, typeof(T));
    }
    else
    {
        throw new ArgumentException("Expression must refer to only a Field or a Property", "MemberExpression");
    }
}
public static void AddValue(此SerializationInfo源,表达式MemberExpression)
{
MemberExpression Body=MemberExpression.Body作为MemberExpression;
if(Body==null)
{
UnaryExpression UnaryBody=MemberExpression.Body作为UnaryExpression;
if(一元体!=null)
{
Body=UnaryBody。操作数作为MemberExpression;
}
其他的
{
抛出新ArgumentException(“表达式不是MemberExpression”,“MemberExpression”);
}
}
字符串名称=Body.Member.Name;
如果(Body.Member是FieldInfo)
{
T Value=(T)((FieldInfo)Body.Member).GetValue((ConstantExpression)Body.Expression.Value);
Source.AddValue(名称、值、类型(T));
}
else if(Body.Member为PropertyInfo)
{
T Value=(T)((PropertyInfo)Body.Member).GetValue((ConstantExpression)Body.Expression,null);
Source.AddValue(名称、值、类型(T));
}
其他的
{
抛出新ArgumentException(“表达式必须仅引用字段或属性”、“MemberExpression”);
}
}

当试图从Body.Member中获取值时,我遇到了一个异常,当它是一个属性时(当它是一个字段时,它可以正常工作)。我如何获取该值

其他问题- 1) 我采取的方法有什么问题吗? 2) 有没有更好的办法来处理这整件事? 3) Body.Member何时将成为FieldInfo,何时将成为PropertyInfo


这是我上一个问题的延伸,
AddValue
方法必须如此复杂吗?我想下面的方法也可以。它不使用反射,而是编译和计算lambda表达式以获取值

public static void AddValue<T>(
    this SerializationInfo source, 
    Expression<Func<T>> memberExpression)
{
    MemberExpression body = memberExpression.Body as MemberExpression;
    string name = body.Member.Name;
    Func<T> valFunc = memberExpression.Compile();
    T val = valFunc();

    source.AddValue(name, val, typeof(T));
}
publicstaticvoidaddvalue(
此序列化信息源,
表达式成员(表达式)
{
MemberExpression body=MemberExpression.body作为MemberExpression;
字符串名称=body.Member.name;
Func valFunc=memberExpression.Compile();
T val=valFunc();
source.AddValue(名称、val、类型(T));
}
编辑:为了满足性能敏感的情况,我通常使用两个重载来定义扩展方法:

public static void AddValue<T>(
    this SerializationInfo source,
    Expression<Func<T>> memberExpression)
{
    Func<T> valFunc = memberExpression.Compile();
    T val = valFunc();

    source.AddValue(val, memberExpression);
}

public static void AddValue<T>(
    this SerializationInfo source,
    T val,
    Expression<Func<T>> memberExpression)
{
    MemberExpression body = memberExpression.Body as MemberExpression;
    string name = body.Member.Name;

    source.AddValue(name, val, typeof(T));
}
publicstaticvoidaddvalue(
此序列化信息源,
表达式成员(表达式)
{
Func valFunc=memberExpression.Compile();
T val=valFunc();
source.AddValue(val,memberExpression);
}
公共静态无效附加值(
此序列化信息源,
T val,
表达式成员(表达式)
{
MemberExpression body=MemberExpression.body作为MemberExpression;
字符串名称=body.Member.name;
source.AddValue(名称、val、类型(T));
}
这样,您可以调用以下任一选项:

// Inefficient, since it requires compilation of lambda expression:
info.AddValue<string>(() => Name);

// Faster, but requires you to specify two parameters.
info.AddValue<string>(Name, () => Name);
//效率低下,因为它需要编译lambda表达式:
info.AddValue(()=>名称);
//更快,但需要指定两个参数。
info.AddValue(Name,()=>Name);

后一种重载在其参数中有一定程度的冗余,但可以解决您的性能问题(实际上比基于反射的实现更快),同时仍然保持重构的安全性。

“我在尝试时遇到了一个异常”异常是什么?我只是把它分解了一点,当我将对象值强制转换为T时,异常就发生了-所以它实际上让我从PropertyInfo中获取值,但是我如何将它强制转换为正确的返回类型呢?这个方法的性能如何?我对性能不太敏感,但是如果你编译每个调用,而我在程序中执行了10000次,那么如果这个方法慢得多,这将是一个问题。。。