简体   繁体   中英

Calling Base Class Method using Reflection.Emit

I have set up my code to define a type, set the parent type as well as implement an interface. The problem I am having is that when I go to create the type it says that it cannot find the method implementations for the interface even though those methods are implemented on the parent type. From what I have seen you need to define pass through methods for a situation like this, here is my code to do that:

    public interface IService<TDto, TId>
{
    Task<TId> CreateAsync(TDto entity);
    Task<bool> DeleteAsync(TId id);
    Task<bool> UpdateAsync(TDto entity);
    Task<List<TDto>> GetAllAsync();
    Task<TDto> GetAsync(TId id);
    TDto Get(TId id);
    Task<IEnumerable<TDto>> GetAllPagedAsync(Int32 page, Int32 take);
    Task<Int32> GetCountAsync();
    Task<object> GetForIdsAsync(TId[] ids, Int32? page = null, Int32? pageSize = null);
    object GetForIds(TId[] ids, Int32? page = null, Int32? pageSize = null);
    Task<bool> DeleteForIdsAsync(TId[] ids);
    Task<List<TDto>> CloneEntitiesAsync(List<TDto> dtos);
    Task<IList> GetForTypesAndIdsAsync(List<string> types, List<object[]> typeIds);
    Task<object> GetByConditionsAsync(Query query);
    Task<object> ExceptIdsAsync(TId[] ids, Int32? page = null, Int32? pageSize = null);
    bool Merge(TDto dto);
}

public Type[] CreateServiceType(Type dtoType, Type entityType, ModuleBuilder moduleBuilder)
        {
            string namespaceName = string.Format("Services.{0}", ProfileNamePlural);

            TypeBuilder iserviceTypeBuilder =
                moduleBuilder.DefineType(
                string.Format("{0}.I{1}Service", namespaceName, ClassName), 
                TypeAttributes.Interface | TypeAttributes.Abstract);

            var baseIServiceType = typeof (IService<,>).MakeGenericType(dtoType, entityType);
            iserviceTypeBuilder.AddInterfaceImplementation(baseIServiceType);

            Type iserviceType = iserviceTypeBuilder.CreateType();

            var baseType = typeof(AService<,,>).MakeGenericType(dtoType, entityType, typeof(Guid));

            string serviceClassName = string.Format("{0}.{1}Service", namespaceName, ClassName);

            TypeBuilder serviceTypeBuilder =
                moduleBuilder.DefineType(serviceClassName, TypeAttributes.Public);

            serviceTypeBuilder.SetParent(baseType);

            serviceTypeBuilder
                .AddInterfaceImplementation(iserviceType);

            var repositoryType = typeof(IRepository<>).MakeGenericType(entityType);

            ConstructorBuilder ctorBuilder =
                serviceTypeBuilder.DefineConstructor(
                    MethodAttributes.Public,
                    CallingConventions.Standard,
                    new[] { repositoryType });

            var baseConstructor =
                baseType.GetConstructor(
                BindingFlags.NonPublic | BindingFlags.FlattenHierarchy | BindingFlags.Instance,
                    null, 
                    new[] { repositoryType }, 
                    null);

            var ilGenerator = ctorBuilder.GetILGenerator();

            // Generate constructor code
            ilGenerator.Emit(OpCodes.Ldarg_0);                // push "this" onto stack. 
            ilGenerator.Emit(OpCodes.Ldarg_1);
            ilGenerator.Emit(OpCodes.Call, baseConstructor);
            ilGenerator.Emit(OpCodes.Ret);

            DefinePassThroughs(ref serviceTypeBuilder, baseType, baseIServiceType);

            return new[] { serviceTypeBuilder.CreateType(), iserviceType };
        }

private void DefinePassThroughs(ref TypeBuilder typeBuilder, Type baseType, Type iServiceType)
        {
            var virtualMethods = iServiceType.GetMethods();
            foreach (var imethod in virtualMethods)
            {
                var method = baseType.GetMethod(imethod.Name);
                var paramTypes = method.GetParameters().Select(x => x.ParameterType).ToArray();

                var passThroughMethod =
                    typeBuilder.DefineMethod(
                    method.Name, 
                    MethodAttributes.Public, 
                    CallingConventions.Standard,
                    method.ReturnType,
                    paramTypes);

                var il = passThroughMethod.GetILGenerator();
                il.Emit(OpCodes.Ldarg_0);
                for (var i = 0; i < paramTypes.Length; i++)
                {
                   il.Emit(OpCodes.Ldarg, i + 1); 
                }

                il.EmitCall(OpCodes.Callvirt, method, null);
                il.Emit(OpCodes.Ret);
                typeBuilder.DefineMethodOverride(passThroughMethod, imethod);
            }
        }

When I try to create the type instance I get this error: "Signature of the body and declaration in a method implementation do not match." What am I missing here?

even though those methods are implemented on the parent type.

Since the parent type is already implementing the interface, the derived type does not need the explicit pass throughs (you might need to declare the parents' implementations of the interface as virtual though).

Have a look at that answer: https://stackoverflow.com/a/3621600/1698246

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM