简体   繁体   中英

Find the variance between two Objects in C#

I'm looking for a way to get the variance between two instances of an object. the following function I've written uses reflection to serve the purpose at hand, but i want to enhance it a bit more so it could skip certain fields with specific data annotations. For example the '[NotMapped] & [JsonIgnore]' annotation that is used in Entity Framework Models

    public static List<ChangeSet> GetVariances<T>(this T previous, T updated)
    {
        List<ChangeSet> changeSet = new List<ChangeSet>();
        try
        {
            string[] excludedFields = { "Id", "DateCreated", "DateModified" };
            Type entityType = previous.GetType();
            FieldInfo[] fieldInfo = entityType.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public);
            foreach (FieldInfo x in fieldInfo)
            {
                if (!excludedFields.Any(z => x.Name.Contains(z))){
                    ChangeSet change = new ChangeSet
                    {
                        Field = x.Name,
                        PreviousValue = x.GetValue(previous),
                        UpdatedValue = x.GetValue(updated)
                    };
                    if (!Equals(change.PreviousValue, change.UpdatedValue))
                        changeSet.Add(change);
                }
            }
        }
        catch (Exception ex)
        {
            var exception = ex.Message;
        }
        return changeSet;
    }

Example of a model that is being used:

[Table("ClientMaster")]
public partial class ClientMaster
{
    [Key]
    [JsonProperty(PropertyName = "id")]
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    public long Id { get; set; }

    [JsonProperty(PropertyName = "clientId")]
    [Required, StringLength(250)]
    public string ClientId { get; set; }

    [JsonProperty(PropertyName = "approvalLevel")]
    [Required, StringLength(200)]
    public string ApprovalLevel { get; set; }

    [NotMapped]
    [JsonProperty(PropertyName = "attachments")]
    public List<ClientAttachmentModel> Attachments { get; set; }

    [JsonIgnore]
    public virtual UserInformation CreatedByUser { get; set; }

    [JsonIgnore]
    public virtual UserInformation ModifiedByUser { get; set; }

    [JsonIgnore]
    public virtual ICollection<TaskMaster> TaskMaster { get; set; }
}

Could anyone please guide me to make the function skip certain data annotations. Any help appreciated.

您可以使用Attribute.IsDefined检查字段或属性是否具有Attribute.IsDefined

var hasAttribute = Attribute.IsDefined(x, typeof(NotMappedAttribute));

If what you're after is just finding what attributes are decorating a particular property, you'll need to call GetProperties on your type, instead of GetFields as you currently are. This is because your attributes are decorating properties, and not fields. GetFields will retrieve the compiler-generated backing fields, which probably isn't what you're after. You can still perform your value comparisons in the same way.

Now, to check for attributes, each PropertyInfo object in the array returned by GetProperties will have an array property CustomAttributes , which contains details of that property's decorating attributes and any arguments you've provided to those attributes. If you just want to check for the presence of an attribute and don't care about arguments, Magnus's solution achieves the same and quicker.

(I'll also mention that in your code sample, using Name.Contains will mean that for example, ClientId will be skipped because its name contains Id , which you list as an excluded field. Name will, for properties you've declared, just return the name as declared, so you could just check for equality.)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM