Dapper 및 C # 읽기 전용 자동 속성 (C # 6에서 도입 됨) 과 관련된 다음 동작을 발견했습니다 .
Dapper는 읽기 전용 속성 집합을 사용하여 클래스의 인스턴스를 매핑 할 수 있는데, 읽기 전용 속성이 작동하는 방식에 대한 이해에 따르면 불가능합니다.
다음 코드는이를 실제로 보여줍니다.
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;
};
}
}
}
주석 처리 된 줄 은 예상대로 컴파일 타임 오류 CS0200 을 생성 합니다.
데이터베이스 설정이 필요하지 않고 작동하는 SQL 연결 만 필요합니다 (Postgres를 사용하고 있습니다). GetData에서 반환 된 모델에는 Id 속성이 설정되어 있습니다. Model 클래스의 인스턴스를 수동으로 만들려고하면 읽기 전용이므로 Id 속성을 설정할 수 없습니다.
Dapper가 어떻게 속성을 설정할 수 있는지 궁금합니다. Dapper 리포지토리의 코드를 따라 시도했지만 이해 수준 이상입니다.
나는 마법이 일어나고 있다고 생각하는 SqlMapper.cs # L1530 을 따라갈 수 있었지만 그 지점을 넘어서는 것은 따라 가기가 너무 어렵습니다.
누군가가 간단한 용어로 설명 할 수 있다면 감사 할 것입니다. :)
감사합니다.
내부적으로 선언 :
public long Id { get; }
실제로 다음 C # 코드로 컴파일됩니다.
[CompilerGenerated]
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private readonly long <Id>k__BackingField;
public long Id
{
[CompilerGenerated]
get
{
return <Id>k__BackingField;
}
}
Reflection을 사용하면 꽤 미친 일을 할 수 있습니다. 그리고 그 중 하나는으로 표시된 필드의 값을 설정하는 것입니다 readonly
. (이는 string.Empty
원하는대로 설정할 수 있다는 것과 같은 흥미로운 의미가 있습니다!)
Dapper의 경우 다음을 효과적으로 수행하지만 훨씬 더 많은 오류 검사를 수행합니다.
Model m = <instance of your Model class>;
Type t = m.GetType();
string propertyName = "Id"; // read using Reflection
FieldInfo fi = t.GetField("<" + propertyName + ">k__BackingField",
BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null)
fi.SetValue(m, 22); // 22 = value read from DB
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다