0

I have classes like below. The TestOne method is running but the TestTwo is not running. Because the TestTwo has a parameter. The Activator gives an error. How can I solve this reason ? I need to use together Activator.CreateInstance and Delegate.CreateDelegate ?

public class Foo
{
    public Foo(string name)
    {
        Name = name;
    }

    public string Name { get; set; }
}

public class MyClass
{
    public Lazy<IEnumerable<Foo>> Foos { get; set; }
}

[TestFixture]
public class Test
{
    private IEnumerable<T> CreateItems<T>() where T : class
    {
        for (int i = 0; i < 5; i++)
        {
            yield return (T)Activator.CreateInstance(typeof(T), i.ToString(CultureInfo.InvariantCulture));
        }
    }

    private IEnumerable<T> CreateItems<T>(int count) where T : class
    {
        for (int i = 0; i < count; i++)
        {
            yield return (T)Activator.CreateInstance(typeof(T), i.ToString(CultureInfo.InvariantCulture));
        }
    }

    public IEnumerable<T> TestMethod<T>() where T : class
    {
        return CreateItems<T>();
    }

    public IEnumerable<T> TestMethod2<T>(int i) where T : class
    {
        return CreateItems<T>(i);
    }

    [Test]
    public void TestOne()
    {
        var u = new MyClass();
        var prop = u.GetType().GetProperties().First(x => x.PropertyType.IsGenericType 
            && x.PropertyType.GetGenericTypeDefinition() == typeof(Lazy<>));
        var enu = prop.PropertyType.GetGenericArguments()[0];
        var j = enu.GetGenericArguments()[0];
        var func = typeof(Func<>).MakeGenericType(enu);
        var mi = this.GetType().GetMethod("TestMethod").MakeGenericMethod(j);
        var factory = Delegate.CreateDelegate(func, this, mi);
        var type = typeof(Lazy<>).MakeGenericType(enu);
        prop.SetValue(u, Activator.CreateInstance(type, factory), null);
        Debug.WriteLine("Count:" + u.Foos.Value.Count());
        foreach (var foo in u.Foos.Value)
        {
            Debug.WriteLine(foo.Name);
        }
    }

    [Test]
    public void TestTwo()
    {
        var u = new MyClass();
        var prop = u.GetType().GetProperties().First(x => x.PropertyType.IsGenericType 
            && x.PropertyType.GetGenericTypeDefinition() == typeof(Lazy<>));
        var enu = prop.PropertyType.GetGenericArguments()[0]; 
        var j = enu.GetGenericArguments()[0];
        var func = typeof(Func<,>).MakeGenericType(typeof(int), enu);
        var mi = this.GetType().GetMethod("TestMethod2").MakeGenericMethod(j);
        var factory = Delegate.CreateDelegate(func, this, mi);
        var type = typeof(Lazy<>).MakeGenericType(enu);
        // How do I send parameter to the TestMethos2 ? 
        // I get the error this line.
        prop.SetValue(u, Activator.CreateInstance(type, factory), null);
        Debug.WriteLine("Count:" + u.Foos.Value.Count());
        foreach (var foo in u.Foos.Value)
        {
            Debug.WriteLine(foo.Name);
        }
    }
}
Sinan AKYAZICI
  • 3,942
  • 5
  • 35
  • 60
  • http://www.rhyous.com/2012/06/15/aop-implementing-a-lazy-loading-property-in-csharp-with-postsharp/ – adt Oct 17 '12 at 19:35

2 Answers2

1

When you use Activator.CreateInstance, it will try to find the best constructor for the parameters you supply it. If you provide no parameters, it will search for a parameter-less constructor, which Foo doesn't have.

Since Foo only have a constructor with a string argument, you must provide the same definition to CreateInstance, like this:

Activator.CreateInstance(typeof(Foo), new object[] { "a string" });
LightStriker
  • 19,738
  • 3
  • 23
  • 27
  • He is not trying to create Foo object with Activator. He is trying to create Lazy's delegate... – adt Oct 17 '12 at 19:10
  • Because he's trying to create an instance of Foo in the line "yield return (T)Activator.CreateInstance(typeof(T), i.ToString(CultureInfo.InvariantCulture));" He made a delegate of TestMethod which call CreateItems. – LightStriker Oct 17 '12 at 19:21
  • @adt : Well, if it is the case, he is creating the wrong delegate. But I feel we are missing something here, because nobody would go in such a complicated way to call a method unless there was a very specific situation. – LightStriker Oct 17 '12 at 19:24
  • I think OP is trying to achieve something like Interception without castle proxy. – adt Oct 17 '12 at 19:34
0

Look at here for the constructor info of Lazy.

http://msdn.microsoft.com/en-us/library/dd642331.aspx

public Lazy<IEnumerable<Foo>> Foos { get; set; }

Must be sent a delegate of type of Func<IEnumerable<Foo>> to its constructor for creating Lazy<T>. But in here trying to send a delegate of type of Func<int, IEnumerable<Foo>>.

Creating a delegate of type of Func<IEnumerable<Foo>> for the TestMethod2 is imposible. It is in here.

How to define a delegate using Delegate.CreateDelegate instead of Func<>?

Community
  • 1
  • 1
Sinan AKYAZICI
  • 3,942
  • 5
  • 35
  • 60