DapperLib / DapperLib/DapperAOT
Support non-public constructors
Nobody has claimed this yet.
- Dominant language
- C#
- Stars
- 472
- Forks
- 43
- Avg merge
- 1d 4h
- Merged PRs (30d)
- 18
Description
We already support annotated custom constructors when they're accessible to the generator. We can extend that.
Note: only impacts private and protected constructor usage; all others should continue using direct
This can be implemented acceptably using reflection (ideally optimized via Expression) or [UnsafeAccessor] (net8+ only); example
using System;
using System.Linq.Expressions;
using System.Reflection;
using System.Runtime.CompilerServices;
static class P {
static void Main()
{
var obj = CreateBar(42);
Console.WriteLine(obj.A);
obj = CreateBar(96);
Console.WriteLine(obj.A);
}
#if NET8_0_OR_GREATER
[UnsafeAccessor(UnsafeAccessorKind.Constructor)]
static extern Bar CreateBar(int a);
#else
private static Func<int, Bar>? s_CreateBar;
static Bar CreateBar(int a) => SomeUtilityHelper.GetConstructor(ref s_CreateBar)(a);
#endif
}
static class SomeUtilityHelper // in DapperAOT - maybe in RowFactory?
{
public static TDelegate GetConstructor<TDelegate>(ref TDelegate? field) where TDelegate : Delegate
{
return field ?? SlowCreate(ref field);
static TDelegate SlowCreate(ref TDelegate? field)
{
var signature = typeof(TDelegate).GetMethod(nameof(Action.Invoke));
if (signature?.ReturnType is null || signature.ReturnType == typeof(void))
{
throw new InvalidOperationException("No target-type found");
}
var methodArgs = signature.GetParameters();
var argTypes = Array.ConvertAll(methodArgs, p => p.ParameterType);
var ctor = signature.ReturnType.GetConstructor(
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance, argTypes);
if (ctor is null)
{
throw new InvalidOperationException("No suitable constructor found matching "
+ string.Join<Type>(", ", argTypes));
}
var args = Array.ConvertAll(methodArgs, p => Expression.Parameter(p.ParameterType, p.Name));
field = Expression.Lambda<TDelegate>(Expression.New(ctor, args), args).Compile();
return field;
}
}
}
class Bar
{
private readonly int x;
public int A => x;
private Bar(int a) => x = a;
}
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The issue identifies existing annotated custom-constructor handling and suggests RowFactory as a possible helper location; start there and inspect how constructor accessibility is determined. Verify that private and protected constructors use the new path while accessible constructors remain direct, considering the reflection/Expression and net8+ UnsafeAccessor options shown.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- csharp
- Domain
- tooling
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100