I noticed the following behavior related to Dapper and C# read-only auto-properties (introduced in C# 6).
Dapper is able to map an instance of a class with a read-only property set, which according to my understanding of how read-only properties work should not be possible.
The following code demonstrates this in action:
using Dapper;
using Npgsql;
using System;
using System.Threading.Tasks;
namespace ConsoleApp1
{
class Model
{
public long Id { get; }
}
class Program
{
static async Task<Model> GetData()
{
using (var connection = new NpgsqlConnection("..."))
{
await connection.OpenAsync();
var sql = @"
SELECT 22 AS Id";
return await connection.QuerySingleAsync<Model>(sql);
}
}
static async Task Main(string[] args)
{
var model = await GetData();
Console.WriteLine(model.Id);
var model2 = new Model();
//model2.Id = 22;
var model3 = new Model
{
//Id = 22;
};
}
}
}
The commented out lines produce compile-time error CS0200 as expected.
No database setup is needed, just a working SQL connection (I'm using Postgres). The model returned from GetData has it's Id property set, if I try to manually create an instance of the Model class I can't set it's Id property as it's read-only.
I was wondering how Dapper can set the property anyway ? I tried following the code in the Dapper repo but it's above my level of comprehension.
I managed to follow up-to SqlMapper.cs#L1530 which is where I think the magic is happening, but beyond that point it's just too hard to follow.
If someone could explain in simple terms I would be grateful :)
Thank you.