Commit bebe80bc authored by Marc Gravell's avatar Marc Gravell

Support get-only C# 6 properties, i.e. `public int Id {get;}`

parent b9288b4a
......@@ -14,7 +14,9 @@
<PropertyGroup>
<SchemaVersion>2.0</SchemaVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<ProduceOutputsOnBuild>True</ProduceOutputsOnBuild>
</PropertyGroup>
<ItemGroup>
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
</ItemGroup>
......
......@@ -3696,5 +3696,17 @@ protected static SqliteConnection GetSqliteConnection(bool open = true)
return connection;
}
#endif
}
[Fact]
public void GetOnlyProperties()
{
var obj = connection.QuerySingle<HazGetOnly>("select 42 as [Id], 'def' as [Name];");
obj.Id.IsEqualTo(42);
obj.Name.IsEqualTo("def");
}
class HazGetOnly
{
public int Id { get; }
public string Name { get; } = "abc";
}
}
}
......@@ -164,13 +164,25 @@ public SqlMapper.IMemberMap GetMember(string columnName)
if (property != null)
return new SimpleMemberMap(columnName, property);
// roslyn automatically implemented properties, in particular for get-only properties: <{Name}>k__BackingField;
var backingFieldName = $"<{columnName}>k__BackingField";
// preference order is:
// exact match over underscre match, backing fields over regular fields, exact case over wrong case
var field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase));
?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName, StringComparison.OrdinalIgnoreCase))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
if (field == null && MatchNamesWithUnderscores)
{
field = _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, columnName.Replace("_", ""), StringComparison.OrdinalIgnoreCase));
var effectiveColumnName = columnName.Replace("_", "");
backingFieldName = $"<{effectiveColumnName}>k__BackingField";
field = _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, effectiveColumnName, StringComparison.OrdinalIgnoreCase))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.Ordinal))
?? _fields.FirstOrDefault(p => string.Equals(p.Name, backingFieldName, StringComparison.OrdinalIgnoreCase));
}
if (field != null)
......
......@@ -2798,7 +2798,7 @@ static LocalBuilder GetTempLocal(ILGenerator il, ref Dictionary<Type, LocalBuild
)
{
var returnType = type.IsValueType() ? typeof(object) : type;
var dm = new DynamicMethod($"Deserialize{Guid.NewGuid()}", returnType, new[] { typeof(IDataReader) }, true);
var dm = new DynamicMethod($"Deserialize{Guid.NewGuid()}", returnType, new[] { typeof(IDataReader) }, type, true);
var il = dm.GetILGenerator();
il.DeclareLocal(typeof(int));
il.DeclareLocal(type);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment