另一种选择(也是我个人的偏好)是简单地将System.Web.Script.Serialization.ScriptIgnoreAttribute 放在您不想序列化的模型类的成员上(或创建一个可隐式转换的 DTO 类来做同样的事情)。
例如:
using System.Web.Script.Serialization;
public class User
{
[ScriptIgnore]
public int ID { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
这样你就不需要定义一个特殊的接口,你可以把这个元数据直接放在你的模型中。
更新:显然这不是一个选项,因为该类是派生类,并且它是应该隐藏的(不可修改的)基类的成员。
可以按照你想要的方式动态生成一个类,或者使用Emit 或者像Castle 这样的动态代理库,但是会非常麻烦。如果可以的话,我真的建议使用简单的代理类:
public class UserResult
{
public UserResult(User user)
{
Username = user.Username;
Password = user.Password;
}
public string Username { get; set; }
public string Password { get; set; }
}
或者,如果您真的无法处理维护这个问题,您可以构建一个“通用”代理实例化器:
static class ProxyInstantiator
{
public static TProxy CreateProxy<TProxy>(object source)
where TProxy : new()
{
TProxy proxy = new TProxy();
CopyProperties(source, proxy);
return proxy;
}
protected static void CopyProperties(object source, object dest)
{
if (dest == null)
{
throw new ArgumentNullException("dest");
}
if (source == null)
{
return;
}
Type sourceType = source.GetType();
PropertyInfo[] sourceProperties =
sourceType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
Type destType = dest.GetType();
PropertyInfo[] destProperties =
destType.GetProperties(BindingFlags.Instance | BindingFlags.Public);
var propsToCopy =
from sp in sourceProperties
join dp in destProperties on sp.Name equals dp.Name
select new { SourceProperty = sp, DestProperty = dp };
foreach (var p in propsToCopy)
{
object sourceValue = p.SourceProperty.GetValue(o, null);
p.DestProperty.SetValue(dest, sourceValue, null);
}
}
}
然后你可以写一个简单的代理类(不是接口):
public class UserResult
{
public string Username { get; set; }
public string Password { get; set; }
}
并在控制器方法中调用它,如下所示:
User someUser = GetSomeUser();
UserResult result = ProxyInstantiator.CreateProxy<UserResult>(someUser);
请注意:
这不考虑到索引属性,如果有其中任何一个,则会失败。它没有考虑“深度复制”——如果你的源类包含引用类型,它只会复制引用——也许这就是你想要的,也许不是。
就个人而言,我会采用前一种方法,只构建单独的代理类而不使用通用代理,因为如果我犯了错误,我更喜欢编译时错误而不是运行时错误。但是你问了,所以你去!