Click here to Skip to main content
16,022,069 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I'm trying to using expression to create object instance, but i got an error 'System.Reflection.TargetParameterCountException'.
my code is bellow , and i don't know what's the problem, please help.

What I have tried:

using BenchmarkDotNet.Attributes;
using FastExpressionCompiler.LightExpression;
using FastMember;
using System;
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using static FastExpressionCompiler.LightExpression.ExpressionCompiler;

namespace ConsoleApp2
{
    public class Program
    {
        static void Main(string[] args)
        {


            TestExpressionCreate<UserInfo, int>();
            TestActivatorCreate();


            //var summary = BenchmarkRunner.Run<Program>();

            Console.ReadLine();
        }

        #region 

        [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
        public class FieldAttribute : Attribute
        {
            private bool _isSizeExtracted;
            private string _size;

            public FieldAttribute(string dataType = null)
            {
                if (!string.IsNullOrWhiteSpace(dataType))
                {
                    DataType = dataType.ToLower();
                }
            }

            public int? Index { get; set; }

            public string FieldName { get; set; }

            public bool HasDefaultValue { get; set; }

            public string DataType { get; set; }

            internal string Size
            {
                get
                {
                    if (string.IsNullOrWhiteSpace(DataType)) return null;

                    if (!_isSizeExtracted)
                    {
                        _isSizeExtracted = true;

                        var i = DataType.IndexOf('(');
                        if (i > 0)
                        {
                            var j = DataType.IndexOf(')', i);
                            if (j > 0)
                            {
                                //_size = DataType[(i + 1)..j];
                            }
                        }
                    }

                    return _size;
                }
            }
        }

        internal class TableInfo
        {

        }

        internal class FieldInfoBase
        {
            internal int Index { get; set; }

            internal string FieldName { get; set; }

            internal bool HasDefaultValue { get; set; }

            internal string FieldDataType { get; set; }

            internal Type PropertyType { get; set; }

            internal string Size { get; set; }

            internal bool FieldNameSameAsPropertyName { get; set; }

            internal virtual object GetValue(object objInstance) { return null; }
        }

        internal class FieldInfo<TUserData, TValue> : FieldInfoBase where TUserData : class
        {
            private ConcurrentDictionary<Type, long[]> _hashes = null;

            protected bool _isValueType;

            protected Type _realPropertyType;

            public FieldInfo(TableInfo tableInfo, PropertyInfo propertyInfo, FieldAttribute attr, ref int columnIndex)
            {
                _hashes = new ConcurrentDictionary<Type, long[]>();

                HasDefaultValue = attr.HasDefaultValue;
                Size = attr.Size;
                FieldDataType = attr.DataType;
                Index = attr.Index ?? columnIndex++;

                PropertyName = propertyInfo.Name;
                PropertyType = propertyInfo.PropertyType;

                FieldName = string.IsNullOrWhiteSpace(attr.FieldName) ? PropertyName : attr.FieldName;

                FieldNameSameAsPropertyName = PropertyName.Equals(attr.FieldName);


                if (!IsNullable && !_isValueType)
                {
                    IsNullable = true;
                }
            }

            internal string PropertyName { get; private set; }

            internal bool IsPrimaryKey { get; set; }

            internal bool IsNullable { get; set; }

            public void SetValue(TUserData ins, TValue value)
            {

            }
        }

        public class UserInfo
        {
            [Field]
            public int Id { get; set; }

            public int ParentId { get; set; }

            public string Address { get; set; }
        }

        private const int threadCount = 1;

        //private const int max = 10; //500
        //private const int max = 1000; //1k
        //private const int max = 10000; //1w
        //private const int max = 100000; //10w
        private const int max = 1000000; //100w


        //[Benchmark]
        public static void TestExpressionCreate<TUserData, TValue>() where TUserData : class
        {
            var t = typeof(FieldInfo<,>);
            var d = t.MakeGenericType(typeof(TUserData), typeof(TValue));

            var ctor = d.GetConstructor([typeof(TableInfo), typeof(PropertyInfo), typeof(FieldAttribute), typeof(int).MakeByRefType()]);

            var tiExp = Expression.Parameter(typeof(TableInfo));
            var piExp = Expression.Parameter(typeof(PropertyInfo));
            var attrExp = Expression.Parameter(typeof(FieldAttribute));
            var indexExp = Expression.Parameter(typeof(int).MakeByRefType());

            var body = Expression.New(ctor, [tiExp, piExp, attrExp, indexExp]);
            var lambda = Expression.Lambda<Func<FieldInfo<TUserData, TValue>>>(body, [tiExp, piExp, attrExp, indexExp]).CompileFast();


            var table = new TableInfo();
            var pi = typeof(UserInfo).GetProperty("Id");
            var fieldAttr = pi.GetCustomAttribute<FieldAttribute>();
            var columnIndex = 0;

            Stopwatch watch = Stopwatch.StartNew();

            for (int i = 0; i < max; i++)
            {
                var ins = lambda.DynamicInvoke([table, pi, fieldAttr, columnIndex]);
            }

            watch.Stop();
            Console.WriteLine(watch.ElapsedTicks);
        }

        //[Benchmark]
        public static void TestActivatorCreate()
        {
            var t = typeof(FieldInfo<,>);

            var d = t.MakeGenericType(typeof(UserInfo), typeof(int));

            var table = new TableInfo();
            var pi = typeof(UserInfo).GetProperty("Id");
            var fieldAttr = pi.GetCustomAttribute<FieldAttribute>();
            var columnIndex = 0;

            Stopwatch watch = Stopwatch.StartNew();
            for (int i = 0; i < max; i++)
            {
                var x = Activator.CreateInstance(d, [table, pi, fieldAttr, columnIndex]);
            }
            watch.Stop();
            Console.WriteLine(watch.ElapsedTicks);
        }
        #endregion
    }
}
Posted
Updated 4-Oct-24 21:50pm
v2
Comments
[no name] 5-Oct-24 5:02am    
Which line in all that code is causing the problem?
goldli88 5-Oct-24 5:50am    
var ins = lambda.DynamicInvoke([table, pi, fieldAttr, columnIndex]);
here
[no name] 5-Oct-24 5:58am    
The exception is saying that you have the wrong number of parameters in your call.
goldli88 5-Oct-24 6:05am    
yes, i know that. but , i don't know how to fix the problem. The code is my first try using expression to create object .

I googled for
C# pass ref parameter to func<>
,and found a post thread
Quote:
Func delegate with ref variable
[^] , it suggested using delegate. After defined a delegate
private delegate FieldInfo<TUserData, TValue> expCreate<TUserData, TValue>(TableInfo p0, PropertyInfo p1, FieldAttribute p3, ref int p4) where TUserData : class;
and change lambda variable to
var lambda = Expression.Lambda<expCreate<TUserData, TValue>>(body, [tiExp, piExp, attrExp, indexExp]).CompileFast();
, then all code works fine.
 
Share this answer
 
I can't answer this question completely, but can probably help nudge you along with it.

Firstly this line:

var lambda = FastExpressionCompiler.LightExpression.Expression.Lambda<Func<FieldInfo<TUserData, TValue>>>(body, tiExp, piExp, attrExp, indexExp).CompileFast();

'var' sometimes hides things a bit, and its clearer when you specify the type explicitly:

Func<FieldInfo<TUserData, TValue>> lambda = FastExpressionCompiler.LightExpression.Expression.Lambda<Func<FieldInfo<TUserData, TValue>>>(body, tiExp, piExp, attrExp, indexExp).CompileFast();


So, here lambda is a delegate which returns a FieldInfo<t1,t2> but takes no parameters, which is why you are getting parameter mismatch exceptions. I think what you need is:

var lambda = FastExpressionCompiler.LightExpression.Expression.Lambda<Func<TableInfo, PropertyInfo, FieldAttribute, int, FieldInfo<TUserData, TValue>>>(body, tiExp, piExp, attrExp, indexExp).CompileFast();


Now, when I tried that the parameter count mismatch went away but got an 'invalid program' error instead which is about the worst possible error I can think of. I had a hunch that it was to do with the last byref parameter, so I changed it not be a 'ref int' and just an 'int' and then sure enough I could create the objects in the loop.

I then realised that I'd never seen a ref in a Func before, and have concluded I'd have to sit down and think about that quite a lot. Is it rare or impossible? So two issues, the Func<> wasn't declared right and the byref needs some thought...
 
Share this answer
 
Comments
goldli88 5-Oct-24 7:42am    
thanks for trying. i think the question is complicated

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900