Replacing MemberInitExpression

  • Thread starter Thread starter bittercoder
  • Start date Start date
B

bittercoder

I have an Lambda expression which is effectively a
MemberInitExpression... recursively creating a tree of types i.e.

Init(Expression<Func<Dog>> expr) { ...}


Init( () => new Dog()
{
Name = "Bill",
Fleas =
{
new Flea() { Name = "Murray"},
new Flea() { Name = "John" }
}
});

What I'd like to do is actually replace the MemberInitExpression (and
the corresponding NewExpression) with a call to an external static
factory method... (say using MethodCallExpression) yet still retain
all the member bindings... and be able to walk the expression tree
doing it for all MemberInit expressions (so new Dog() would become
Factory.Create<Dog>, new Flea() would become Factory.Create<Flea>
etc.)

Anyone have any suggestions on how to do that easily - I've had a
quick experiment, but couldn't see any easy way to retain all the
existing MemberBindings.

Chez,

- Alex
 
Not while retaining the expression approach; you'd essentially need it
to do:

Dog dog = Factory.Create<Dog>();
dog.Name = "Bill";
Flea flea = Factory.Create<Flea>();
flea.Name = "Murray";
dog.Fleas.Add(flea);
flea = Factory.Create<Flea>();
flea.Name = "John";
dog.Fleas.Add(flea);
return dog;

However, you simply can't do that in an expression!
MemberInit wants to create things (ctor), and MemberBind wants to read
them...

So: what is your factory doing? What is its purpose? There may be
other ways to crack this problem... if the factory is creating
subclassed entities, then perhaps something involving generics with
"TDog : new(), TFlea : new()"; if it is pre-configuring them, then put
that code in the standard ctor.

Perhaps post back with more info?

Marc
 
For info, if yo don't mind writing the long-hand, there are some
things you can do without Expression, but just with Func (see
below)...

Again, however - I think you need to give more info on what you are
trying to achieve ;-p

Marc

interface IFoo
{
int Id { set; }
}
class Dog : IFoo
{
public int Id { get; set; }
public string Name { get; set; }
private readonly List<Flea> fleas = new List<Flea>();
public List<Flea> Fleas { get { return fleas; } }
}
class Flea : IFoo
{
public int Id { get; set; }
public string Name { get; set; }
}
class Factory
{
static int nextId;
public static T Create<T>() where T : IFoo, new()
{ // yours to do...
T t = new T();
t.Id = Interlocked.Increment(ref nextId);
return t;
}
}
class Program
{
static void Main(string[] args)
{
Func<Dog> exp = Test(Factory.Create<Dog>,
Factory.Create<Flea>);
CreateAndShow(exp);
CreateAndShow(exp);
CreateAndShow(exp);
}

static Func<Dog> Test(Func<Dog> dogCtor, Func<Flea> fleaCtor)
{
return () =>
{
Dog dog = dogCtor();
dog.Name = "Bill";
Flea flea = fleaCtor();
flea.Name = "Murray";
dog.Fleas.Add(flea);
flea = Factory.Create<Flea>();
flea.Name = "John";
dog.Fleas.Add(flea);
return dog;
};
}

static void CreateAndShow(Func<Dog> expr)
{
Dog dog = expr();
Console.WriteLine("{0}: {1} {2}", dog.Name, dog.Id,
dog.GetType().Name);
foreach (Flea flea in dog.Fleas)
{
Console.WriteLine("{0}: {1} {2}", flea.Name, flea.Id,
flea.GetType().Name);
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top