Pergunta

I have this:

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity, 
    Expression<Func<T, T, bool>> keyComparer) where T : class
{
    entity = repository.GetAll().Single(x => x.Id == entity.Id);
}

[TestMethod]
public void ReadTest_DataFieldGroup()
{
    AssertReadWorks(
            _unitOfWork.DataFieldSetRepository, 
            new DataFieldSet { Label = "test", Title = "test" }, 
            (a, b) => a.Id == b.Id);
}

This does not compile since it is not known that T has an Id property. Note that the keyComparer parameter is not used at the moment. I want to use the keyComparer parameter (or another appropriate parameter) to dynamically generate the predicate for Single():

Expression<Func<T, bool>> keyComparingPredicate = 
    x => a predicate that compares the key of x with the key of `entity`;
entity = repository.GetAll().Single(keyComparingPredicate);

The point is that not all Ts will have Id properties, some will have different names, some will have composite keys. The original AssertReadWorks() works fine if it is not generic. The problem is just building the predicate dynamically in the generic case. If it can be done with something different from the keyComparer paramter, fine with me.

Any ideas? :)

Foi útil?

Solução

Check, if this fits for you

public T AssertReadWorks<T>(
    IRepository<T> repository,
    Func<T, bool> keyComparer)
{
    return repository.GetAll().Single(keyComparer);
}

Using

[TestMethod]
public void TestInt()
{
    var repository = new Repository<int>( new[] {1, 2, 3} );
    var intEntity = 3;
    AssertReadWorks(repository, e => e == intEntity);
}

[TestMethod]
public void TestString()
{
    var repository = new Repository<string>(new[] { "a", "b", "c" });
    var stringEntity = "A";
    AssertReadWorks(repository, e => string.Equals(e, stringEntity, StringComparison.OrdinalIgnoreCase));
}

[TestMethod]
public void TestThread()
{
    var threadEntity = new Thread(() => { });
    var repository = new Repository<Thread>(new[] { threadEntity, new Thread(() => { }), new Thread(() => { }) });
    AssertReadWorks(repository, e => e.ManagedThreadId == threadEntity.ManagedThreadId);
}

EDIT: Response for comment:

public void AssertReadWorks<T>(
    IRepository<T> repository,
    ref T entity,
    Func<T, T, bool> keyComparer)
{
    var localEntity = entity;
    entity = repository.GetAll().Single(e => keyComparer(e, localEntity));
}

Outras dicas

Correct me if I'm wrong but is the whole point of this function to check equality? To do this in a generic sense you can use IEquatable Interface. This way your objects knows how to compare themselves to the same object. This should cut down your code reuse and help avoid creating the same expression in multiple places.

So your class would look like this:

public class DataFieldSet : IEquatable<DataFieldSet>
{
    public int Id { get; set; }

    public bool Equals(DataFieldSet other)
    {
        return other != null && this.Id == other.Id;
    }
}

And your Assert function

public void AssertReadWorks<T>(
    IRepository<T> repository, 
    T entity) where T : IEquatable<T>
{
    entity = repository.GetAll().Single(x => entity.Equals(x);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top