C# 自定义 DynamicObject 转换为派生对象
C# Custom DynamicObject cast to derived object
我有一个 class DocumentObject,它扩展了 DynamicObject 以允许动态成员属性。
public class DocumentObject : DynamicObject
{
/// <summary>
/// Inner dictionary that holds the dynamic members of the object
/// </summary>
Dictionary<string, object> dictionary = new Dictionary<string, object>();
/// <summary>
/// Try to get the member that is not defined in the class (additional dynamic members) from inner dictionary
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
/// <summary>
/// Try to set the member that is not defined in the class (additional dynamic members) to inner dictionary
/// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
/// <summary>
/// Get the names of all the dynamic members
/// </summary>
/// <returns></returns>
public override IEnumerable<string> GetDynamicMemberNames()
{
return dictionary.Keys;
}
}
我有一个继承 DocumentObject
的基础 Person class
public class PersonDto : DocumentObject
{
[JsonProperty("id")]
public string Id { get; set; }
}
继承 PersonDto
的另一个子 OfficePersonDto class
public class OfficePersonDto : PersonDto
{
[JsonProperty("name")]
public string Name { get; set; }
}
在我的函数中,我收到 JSON 对象,该对象必须至少是 PersonDto 对象,但如果它是 OfficePersonDto 类型,我希望能够将 PersonDto 转换为 OfficePersonDto。
IE。 JSON = {"Id":1, "Name": "Orchard"}
,在PersonDto中,name
属性将使用DocumentObject的字典保存,而转换为OfficePersonDto时,Id
和name
都是class的属性。
我如何从 PersonDto 转换为子 class 例如OfficePersonDto?
PersonDto personDto = ...
OfficePersonDto off = personDto as OfficePersonDto // results in null or Name is null
Automapper 当问题与此类转换有关时非常有用。
我将向您展示一个快速的工作示例。但它当然仍会开放以进行更多重构。
PersonDto personDto = ...
// Do not use the following conversion, instead get help from automapper
// OfficePersonDto off = personDto as OfficePersonDto
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PersonDto, OfficePersonDto>()
.ForMember(d => d.Name, opt => opt.MapFrom(new OfficePersonNameResolver()));
});
var mapper = config.CreateMapper();
var off = mapper.Map<OfficePersonDto>(personDto); // off is created with correct values
OfficePersonNameResolver 是这样的:
public class OfficePersonNameResolver : IValueResolver<PersonDto, OfficePersonDto, string>
{
public string Resolve(PersonDto source, OfficePersonDto destination, string destMember, ResolutionContext context)
{
return (source as dynamic).Name;
}
}
如果您对此有任何疑问,欢迎提问。
编辑:将解析器概括为 IValueResolver
像这样更改配置的创建:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PersonDto, OfficePersonDto>()
.ForMember(d => d.Name, opt => opt.MapFrom(new DynamicObjectValueResolver<PersonDto, OfficePersonDto, string>("name")));
});
值解析器现在应该是这样的:
public class DynamicObjectValueResolver<TSource, TDestination, TDestinationMember> : IValueResolver<TSource, TDestination, TDestinationMember>
where TDestinationMember : class
{
private readonly string _propertyName;
public DynamicObjectValueResolver(string propertyName)
{
_propertyName = propertyName;
}
public TDestinationMember Resolve(TSource source, TDestination destination, TDestinationMember destMember, ResolutionContext context)
{
dynamic eo = JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(source));
IDictionary<string, object> dictionary = eo;
return dictionary[_propertyName] as TDestinationMember;
}
}
我有一个 class DocumentObject,它扩展了 DynamicObject 以允许动态成员属性。
public class DocumentObject : DynamicObject
{
/// <summary>
/// Inner dictionary that holds the dynamic members of the object
/// </summary>
Dictionary<string, object> dictionary = new Dictionary<string, object>();
/// <summary>
/// Try to get the member that is not defined in the class (additional dynamic members) from inner dictionary
/// </summary>
/// <param name="binder"></param>
/// <param name="result"></param>
/// <returns></returns>
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
string name = binder.Name.ToLower();
// If the property name is found in a dictionary,
// set the result parameter to the property value and return true.
// Otherwise, return false.
return dictionary.TryGetValue(name, out result);
}
/// <summary>
/// Try to set the member that is not defined in the class (additional dynamic members) to inner dictionary
/// </summary>
/// <param name="binder"></param>
/// <param name="value"></param>
/// <returns></returns>
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// Converting the property name to lowercase
// so that property names become case-insensitive.
dictionary[binder.Name.ToLower()] = value;
// You can always add a value to a dictionary,
// so this method always returns true.
return true;
}
/// <summary>
/// Get the names of all the dynamic members
/// </summary>
/// <returns></returns>
public override IEnumerable<string> GetDynamicMemberNames()
{
return dictionary.Keys;
}
}
我有一个继承 DocumentObject
的基础 Person classpublic class PersonDto : DocumentObject
{
[JsonProperty("id")]
public string Id { get; set; }
}
继承 PersonDto
的另一个子 OfficePersonDto classpublic class OfficePersonDto : PersonDto
{
[JsonProperty("name")]
public string Name { get; set; }
}
在我的函数中,我收到 JSON 对象,该对象必须至少是 PersonDto 对象,但如果它是 OfficePersonDto 类型,我希望能够将 PersonDto 转换为 OfficePersonDto。
IE。 JSON = {"Id":1, "Name": "Orchard"}
,在PersonDto中,name
属性将使用DocumentObject的字典保存,而转换为OfficePersonDto时,Id
和name
都是class的属性。
我如何从 PersonDto 转换为子 class 例如OfficePersonDto?
PersonDto personDto = ...
OfficePersonDto off = personDto as OfficePersonDto // results in null or Name is null
Automapper 当问题与此类转换有关时非常有用。 我将向您展示一个快速的工作示例。但它当然仍会开放以进行更多重构。
PersonDto personDto = ...
// Do not use the following conversion, instead get help from automapper
// OfficePersonDto off = personDto as OfficePersonDto
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PersonDto, OfficePersonDto>()
.ForMember(d => d.Name, opt => opt.MapFrom(new OfficePersonNameResolver()));
});
var mapper = config.CreateMapper();
var off = mapper.Map<OfficePersonDto>(personDto); // off is created with correct values
OfficePersonNameResolver 是这样的:
public class OfficePersonNameResolver : IValueResolver<PersonDto, OfficePersonDto, string>
{
public string Resolve(PersonDto source, OfficePersonDto destination, string destMember, ResolutionContext context)
{
return (source as dynamic).Name;
}
}
如果您对此有任何疑问,欢迎提问。
编辑:将解析器概括为 IValueResolver
像这样更改配置的创建:
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<PersonDto, OfficePersonDto>()
.ForMember(d => d.Name, opt => opt.MapFrom(new DynamicObjectValueResolver<PersonDto, OfficePersonDto, string>("name")));
});
值解析器现在应该是这样的:
public class DynamicObjectValueResolver<TSource, TDestination, TDestinationMember> : IValueResolver<TSource, TDestination, TDestinationMember>
where TDestinationMember : class
{
private readonly string _propertyName;
public DynamicObjectValueResolver(string propertyName)
{
_propertyName = propertyName;
}
public TDestinationMember Resolve(TSource source, TDestination destination, TDestinationMember destMember, ResolutionContext context)
{
dynamic eo = JsonConvert.DeserializeObject<ExpandoObject>(JsonConvert.SerializeObject(source));
IDictionary<string, object> dictionary = eo;
return dictionary[_propertyName] as TDestinationMember;
}
}