Amir Rezaei
Amir Rezaei

Reputation: 5086

Is it possible to have an array of unknown types?

public static bool Compare<T>(this T source, T other, params Expression<Func<T>>[] propertiesToSkip)
{
    PropertyInfo[] sourceProperties = source.GetType().GetProperties();
    List<string> lstPropertiesToSkip = (from x in propertiesToSkip select ((MemberExpression)((UnaryExpression)x.Body).Operand).Member.Name).ToList();
    return !(sourceProperties.Any(sourcePropertyInfo => !lstPropertiesToSkip.Contains(sourcePropertyInfo.Name) && (!sourcePropertyInfo.GetValue(source, null).Equals(sourcePropertyInfo.GetValue(other, null)))));
}

I want to be able to call this function by.

var source = new MyClass();
var other = new MyClass();
source.Compare<MyClass>(other, ()=>SkipProperty1, ()=>SkipProperty2);

The problem is ()=>SkipProperty1 and ()=>SkipProperty2 are not of type MyClass. I need:

Compare <A,B,C,D...>  
params Expression<Func<T>>[] where T is A,B,C,D,E...

I have looked at AutoMapper, with fluent syntax.

public IMappingExpression<TSource, TDestination> ForMember(string name, Action<IMemberConfigurationExpression<TSource>> memberOptions);

Mapper.CreateMap<MyClass, MyClass>()
            .ForMember(dest => dest.Property1, opt => opt.Ignore())
            .ForMember(dest => dest.Property2, opt => opt.Ignore()));

- Can I change the signature of Compare to make the function work?

- Is there other way to solving this? For example using fluent syntax

Note I don't want to send property names as strings.

Upvotes: 3

Views: 177

Answers (1)

Tomas Petricek
Tomas Petricek

Reputation: 243041

One option would be to change the signature of your param arguments to be lambda expressions that return object. Something like this:

public static bool Compare<T>
  (this T source, T other, params Expression<Func<object>>[] propertiesToSkip)

This should work fine, because any .NET type can be cast or boxed to object. You'll need to slightly adjust your code to extract PropertyInfo from the lambda expressions (because there will be additional boxing or cast).

Using fluent syntax should work as well. You'll need some type to pass around:

class SkipComparison<T> {
  public T Source { get; set; }
  public T Other { get; set; }
  public List<PropertyInfo> PropertiesToSkip { get; set; }

  public SkipComparison<T> Skip<R>(Expression<Func<R>> f)
    // TODO: Extract property info, add it to 
    // 'PropertiesToSkip' and 'return this;'
  public bool Run()
    // TODO: Actually perform the comparison here
}

Your Compare method will return a new instance of this class with just Source and Other set and you'll use the Skip method to add additional properties to be skipped.

Upvotes: 2

Related Questions