.netreflectionormdappergetter-setter

How Dapper sets properties without setters


I have a model:

    public class Model
    {
        public int Id { get;}

        public string Name { get; }

        public string AnotherName { get; }
    }

default constructor, no setters, so that we have no public setter method in a generated class by IL.

BUT Dapper somehow initialize my data. All properties are filled.

                var sql = $@"SELECT id as Id, name as Name, another_name as AnotherName FROM dapper";

                var raws = (connection.QueryAsync<Model>(sql).Result).AsList();

I've found source code and they setting by Setter method, but when I tried to get setter as Dapper does, I've got null methodInfo. Here is some Dapper source code SqlMapper:3320

                    if (specializedConstructor == null)
                    {
                        // Store the value in the property/field
                        if (item.Property != null)
                        {
                            il.Emit(type.IsValueType ? OpCodes.Call : OpCodes.Callvirt, DefaultTypeMap.GetPropertySetter(item.Property, type));
                        }
                        else
                        {
                            il.Emit(OpCodes.Stfld, item.Field); // stack is now [target]
                        }
                    }

and the DefaultTypeMap.GetPropertySetter:

        internal static MethodInfo GetPropertySetter(PropertyInfo propertyInfo, Type type)
        {
            if (propertyInfo.DeclaringType == type) return propertyInfo.GetSetMethod(true);

            return propertyInfo.DeclaringType.GetProperty(
                   propertyInfo.Name,
                   BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance,
                   Type.DefaultBinder,
                   propertyInfo.PropertyType,
                   propertyInfo.GetIndexParameters().Select(p => p.ParameterType).ToArray(),
                   null).GetSetMethod(true);
        }

You can write sample so did I, and you'll see if your property doesn't have any setter, then setter method info will be null.


Solution

  • https://github.com/StackExchange/Dapper/blob/main/Dapper/SqlMapper.cs#L3312-L3323
    source code

    It stores property in the internal Dapper model; and if the property doesn't have a setter, it sets it via the backing field.