3

I have an object that his instance is created on runtime like this:

var type = GetTypeFromAssembly(typeName, fullNameSpaceType);
        var instanceOfMyType = Activator.CreateInstance(type);
        ReadObject(instanceOfMyType.GetType().GetProperties(), instanceOfMyType, fullNameSpaceType);
        return instanceOfMyType;

And I need to find an object by Id, for this I have built the follow method:

var parameter = Expression.Parameter(typeof(object));

        var condition =
            Expression.Lambda<Func<object, bool>>(
                Expression.Equal(
                    Expression.Property(parameter, theEntity.GetType().GetProperty("Id").Name),
                    Expression.Constant(id, typeof(TKey))
                    ), parameter
                ).Compile();

But throws an unhandled exception that says:

The instance property 'Id' is not defined for type 'System.Object'

So, how I can built a Func with T where T is seted on runtime ?? Something like this:

var parameter = Expression.Parameter(typeof(MyObjectReflectionRuntimeType>));

        var condition =
            Expression.Lambda<Func<MyObjectReflectionRuntimeType, bool>>(
                Expression.Equal(
                    Expression.Property(parameter, theEntity.GetType().GetProperty("Id").Name),
                    Expression.Constant(id, typeof(TKey))
                    ), parameter
                ).Compile();

UPDATE [Solution with out Entity Framework]

I have made the follow:

    public interface IBaseObject<T>
{
    T Id { get; set; }
}

    public class AnyClass : IBaseObject<Guid>
{
    public Guid Id { get; set; }
}

 var parameter = Expression.Parameter(typeof(IBaseObject<Guid>));
        var id = Guid.NewGuid();
        var theEntity = new AnyClass();

        var theList = new List<AnyClass>
        {
            new AnyClass
            {
                Id = Guid.NewGuid()
            },

            new AnyClass
            {
                Id = Guid.NewGuid()
            },

            new AnyClass
            {
                Id = id
            },

            new AnyClass
            {
                Id = Guid.NewGuid()
            }
        };

        var condition =
            Expression.Lambda<Func<IBaseObject<Guid>, bool>>(
                Expression.Equal(
                    Expression.Property(parameter, theEntity.GetType().GetProperty("Id").Name),
                    Expression.Constant(id, typeof(Guid))
                    ), parameter
                ).Compile();

        var theMetaData = theList.Where(condition).FirstOrDefault();

But it crashes on Entity Framework because the IBaseObject<T> its not part of the context :( ...

[UPDATE TWO]

I have find a solution like this but it not optimal (Thanks to @Serge Semenov):

            var parameter = Expression.Parameter(typeof(object));
        var entity = Expression.Convert(parameter, theEntity.GetType());

        var condition =
            Expression.Lambda<Func<object, bool>>(
                Expression.Equal(
                    Expression.Property(entity, theEntity.GetType().GetProperty("Id").Name),
                    Expression.Constant(id, typeof(TKey))
                    ), parameter
                ).Compile();

        var theObject = await _unitOfWork.Set(theEntity.GetType()).ToListAsync();
        return theObject.FirstOrDefault(condition);

I'm say that is not the best way because instead of use await _unitOfWork.Set(theEntity.GetType()).ToListAsync(); I would like to use: await _unitOfWork.Set(theEntity.GetType()).FirstOrDefaultAsync(); but it does not work ...

Any idea ??

  • probably duplicate of [use reflection to call generic](http://stackoverflow.com/questions/232535/how-do-i-use-reflection-to-call-a-generic-method). – Alexei Levenkov Oct 13 '16 at 21:11
  • I don't think that this is a duplicate of that post. – Travis J Oct 13 '16 at 21:12
  • Is not duplicated ... – Freddy Castelblanco Oct 13 '16 at 21:14
  • @FreddyCastelblanco - Well, not an actual duplication, it just means that the question was asked before and a solution exists at that link. However, I do not believe that using `MakeGenericMethod` is the solution here, nor does it seem the question is asking the same thing. – Travis J Oct 13 '16 at 21:15
  • Well I dont think too that `MakeGenericMethod` is the way ... – Freddy Castelblanco Oct 13 '16 at 21:28
  • 1
    Why don't you send the condition as a parameter ? – raven Oct 13 '16 at 21:34
  • 1
    What are you hoping to achieve? Could you explain in layman's terms? – Win Oct 13 '16 at 21:44
  • I want compile a `Expression.Lambda>`, where the `T` could be a type that can be set on runtime using reflection ... – Freddy Castelblanco Oct 13 '16 at 21:45
  • @FreddyCastelblanco - Are you trying to read the primary key of entity classes that all have a ClassNameId? – Travis J Oct 13 '16 at 21:51
  • @FreddyCastelblanco My question is where and how you plan to use it. We can show you alternative route - it might even be better than what you are current doing. – Win Oct 14 '16 at 00:24
  • @Win What I need is execute queries using entity framework but with out specify the entry that I want to apply the query. I need set the entry dinamically and for this Im trying to create the entry using reflection and after set to the `DbContext Set` property, in this case Im trying to get a object entry by a property named `Id` – Freddy Castelblanco Oct 14 '16 at 01:34

1 Answers1

0

You pass an object to your Func<>, but access the Id property defined on other type.

The easiest fix is to cast the object to a type T and then access its properties, like you would do in C# ((T)obj).Id:

var parameter = Expression.Parameter(typeof(object));
var entity = Expression.Convert(parameter, theEntity.GetType());
...
Expression.Property(entity, theEntity.GetType().GetProperty("Id").Name),
...
Serge Semenov
  • 9,232
  • 3
  • 23
  • 24