#c# #reflection #proxy #loading #lazy-evaluation
#c# #отражение #прокси #Загрузка #отложенная оценка
Вопрос:
Привет, я пишу простую библиотеку DLL ORM. Библиотека работает нормально, и я хотел бы добавить некоторые дополнения к отложенной загрузке. Но я не знаю, как это реализовать. У меня есть одно предложение.
В моем orm (у меня есть creator, но неважно) Пользователь должен создать класс БД, который реализует IMapper, и установить класс mapper. Что-нибудь вроде ссылки на это.
public class Person
{
public virtual string Name {get;set;}
public virtual int Age {get; set;}
}
public class DataBase : IMapper
{
MapperSet<Person> Persons = new MapperSet<Person>();
}
Если у нас есть этот класс и настроена строка подключения, мы можем взять данные из базы данных. Это очень похоже на Entity Framework
Person p = Persons.Single(x=>x.Name == "John");
В этот момент я проверю все свойства в классе сопоставления, и если они виртуальные, то верну не этот класс, а класс отложенной загрузки.
Я продумываю одну концепцию. Не возвращается (в этом примере) Класс Person, но класс, который расширяет класс Person и переопределяет все свойства.
public class PersonReturn : Person
{
//here i must create a method who really take the data from db
private string Query = "SELECT TOP(1) FROM Person WHERE Name = 'John'";
private Execute()
{
p = (Person)Db.TableToObject(Query);
}
Person p;
public override string Name
{
get
{
if(p == null)
p = Execute();
return p.Name;
}
set {}
}
//same
public override int Age {get; set;}
}
Пользователь не должен видеть никаких изменений при использовании этого класса (только при отладке он может видеть другой класс), это должно сработать как по волшебству: P
Мои вопросы: 1. Как реализовать отложенную загрузку, например, в Entity Framework, кто-нибудь знает? 2. Есть ли более простой способ из моего предложения? По моей идее, я должен использовать TypeBuilder и использовать исходный код IL — я слышал, что это проблемы со свойствами, которые они не могут использовать обычным способом.
Ответ №1:
Используйте Castle.DynamicProxy (тот же прокси, который использует nhibernate)
Ответ №2:
Отложенная загрузка реализуется путем генерации inheritor во время выполнения и переопределения всех методов.
public class A
{
virtual protected string name { get; set; }
}
public interface IInterceptor
{
object Invoke(MethodInfo method, params object[] arguments);
}
public sealed class AProxy : A
{
static private readonly MethodInfo getname = typeof(A).GetProperty("name", ...).GetGetMethod(true);
static private readonly MethodInfo setname = typeof(A).GetProperty("name", ...).GetSetMethod(true);
private readonly IInterceptor interceptor;
public AProxy(IInterceptor interceptor)
{
this.interceptor = interceptor;
}
override protected string name
{
get { return this.interceptor.Invoke(AProxy.getname); }
set { this.interceptor.Invoke(AProxy.setname, value); }
}
}
Фабрика прокси должна, чтобы
return new AProxy(custominterceptor);
custominterceptor должен получить идентификатор вашей сущности и при первом использовании создать экземпляр A, запросить базу данных для заполнения A и делегировать вызов A.
Должно быть сгенерировано приблизительно (после сборки или во время выполнения с использованием TypeBuilder)