Search code examples
c#reflection.emittypebuilder

How to build constructor


It is not easy for me to build constructor.

I am trying to make second constructor of the code

 public class Sample
{        

    public Sample Parent { get; set; }      
    public Sample(Sample parent)
    {
        Parent = parent;
        Children = new ObservableTestCollection<Sample>(this);
    }      
    public Sample(Sample parent, IEnumerable<Sample> source)
    {
        Parent = parent;
        Children = new ObservableTestCollection<Sample>(this, source);
    }            
    public ObservableTestCollection<Sample> Children { get;  set; }
}

And the source of ObservableTestCollection as follows:

 public class ObservableTestCollection<T> : ObservableCollection<T>
{
    public T Parent;   
    public ObservableTestCollection(T parent):this(parent, Enumerable.Empty<T>())
    {         
    }
    public ObservableTestCollection(T parent, IEnumerable<T> source): base(source) 
    {
      Parent = parent;
    }
}

And the constructor builder I wrote is as follows:

        //first constructor           
        var obsCtor1 = typeOfCts.GetConstructors().First(c => c.GetParameters().Length == 1);
        obsCtor1 = TypeBuilder.GetConstructor(genericTypeOfCts, obsCtor1);
        var constructorParameters = new Type[] { typeBuilder };
        var ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, constructorParameters);
        il = ctorBuilder.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Call, setParentMethod);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Newobj, obsCtor1);
        il.Emit(OpCodes.Call, setChildrenMethod);
        il.Emit(OpCodes.Ret);


        //second constructor
             var obsCtor2 = typeOfCts.GetConstructors().First(c => c.GetParameters().Length == 2);
        obsCtor2 = TypeBuilder.GetConstructor(genericTypeOfCts, obsCtor2);
        var ctorParam = typeOfCts.MakeGenericType(typeBuilder);         
        constructorParameters = new Type[] { typeBuilder, ctorParam };          
        ctorBuilder = typeBuilder.DefineConstructor(MethodAttributes.Public, CallingConventions.HasThis, constructorParameters);
        il = ctorBuilder.GetILGenerator();
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Call, typeof(object).GetConstructor(Type.EmptyTypes));
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_1);
        il.Emit(OpCodes.Call, setParentMethod);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_0);
        il.Emit(OpCodes.Ldarg_2);
        il.Emit(OpCodes.Newobj, obsCtor2);
        il.Emit(OpCodes.Call, setChildrenMethod);
        il.Emit(OpCodes.Ret);

        Type type = typeBuilder.CreateType();
        var obj1 = Activator.CreateInstance(type, new object[] { null });
        var obj2 = Activator.CreateInstance(type, obj1);
        assemblyBuilder.Save(assemblyFileName);

        var children = (IList)obj2.GetType().GetProperty(selfRefDerivedCollectionName).GetValue(obj2, null);
        ((INotifyCollectionChanged)children).CollectionChanged += Program_CollectionChanged;

        var obj3 = Activator.CreateInstance(type, new object[] { null });
        children.Add(obj3);


        var listOf = typeof(List<>);
        var listOfType = listOf.MakeGenericType(type);
        var list =(IList) Activator.CreateInstance(listOfType);
        obj1 = Activator.CreateInstance(type, new object[] { null });
        list.Add(obj1);
        obj1 = Activator.CreateInstance(type, new object[] { null });
        list.Add(obj1);
        var obj4 = Activator.CreateInstance(type, list);

Can somebody help me to find out what's wrong with my code.


Solution

  • I found that the problem was not in building second constructor, but was in making instance of generic type.

    I updated as follows:

            Type type = typeBuilder.CreateType();
            var obj1 = Activator.CreateInstance(type, new object[] { null });
            var obj2 = Activator.CreateInstance(type, obj1);
            assemblyBuilder.Save(assemblyFileName);
    
            var children = (IList)obj2.GetType().GetProperty(selfRefDerivedCollectionName).GetValue(obj2, null);
            ((INotifyCollectionChanged)children).CollectionChanged += Program_CollectionChanged;
    
            var obj3 = Activator.CreateInstance(type, new object[] { null });
            children.Add(obj3);
    
            var genericType = typeOfCts.MakeGenericType(type);
    
    
            var list = Activator.CreateInstance(genericType, new object[] { null});
            obj1 = Activator.CreateInstance(type, new object[] { null });
    
            list.GetType().GetMethod("Add").Invoke(list, new object[] { obj1 });
    
    
            obj1 = Activator.CreateInstance(type, new object[] { null });
            list.GetType().GetMethod("Add").Invoke(list, new object[] { obj1 });
    
            var obj4 = Activator.CreateInstance(type, new object[] { null, list });