Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Вызов GetType() / 14 сообщений из 14, страница 1 из 1
13.11.2012, 20:33
    #38036999
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
Читал тут одну книжку и в ней наткнулся на такой код

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
public abstract class Entity<TId>
{
    public virtual TId Id { get; protected set; }
    public override bool Equals(object obj)
    {
        return Equals(obj as Entity<TId>);
    }

    private static bool IsTransient(Entity<TId> obj)
    {
        return obj != null &&
        Equals(obj.Id, default(TId));
    }

    private Type GetUnproxiedType()
    {
        return GetType();
    }

    public virtual bool Equals(Entity<TId> other)
    {
        if (other == null)
            return false;
        if (ReferenceEquals(this, other))
            return true;
        if (!IsTransient(this) &&
        !IsTransient(other) &&
        Equals(Id, other.Id))
        {
            var otherType = other.GetUnproxiedType();
            var thisType = GetUnproxiedType();
            return thisType.IsAssignableFrom(otherType) ||
            otherType.IsAssignableFrom(thisType);
        }
        return false;
    }

    public override int GetHashCode()
    {
        if (Equals(Id, default(TId)))
            return base.GetHashCode();
        return Id.GetHashCode();
    }
}

public abstract class Entity : Entity<Guid>
{
}



Хотел узнать, а зачем вызов GetUnproxiedType() в Equals? Почему нельзя было просто вызвать other.GetType() и this.GetType()?
...
Рейтинг: 0 / 0
13.11.2012, 23:20
    #38037170
МСУ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
Книжку писал пьяный песатель, видимо. Что за чтиво-то?
...
Рейтинг: 0 / 0
13.11.2012, 23:35
    #38037187
SolYUtor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
МСУКнижку писал пьяный песатель, видимо. Что за чтиво-то?
Сам ты пьяный писатель, но в книжке тоже есть ошибка. Книжка NHibernate CookBook .

Lamo2012Хотел узнать, а зачем вызов GetUnproxiedType() в Equals? Почему нельзя было просто вызвать other.GetType() и this.GetType()?
Дело в том, что NHibernate делает динамические прокси классы, которые наследуют от классов доменной модели. Если вызвать на таком класси GetType(), то это будет не ваш класс, а класс с названием ProxyМногобукв. При этом внутри этого прокси-класса есть ссылка на настоящий класс.
Чтобы сравнить реальные типы и нужен GetUnproxiedType, только он должен быть с модификатором Protected или public. Волшество в том, что при таком раскладе проки-тип перенапривит вызов реальному типу, и вернёт его тип. Но для private методов такое волшебство не работает, т.к. они не переопределятеся прокси-типом. Поэтому private GetUnproxiedType() вернёт ProxyМногобукв, а public или protected GetUnproxiedType() вернёт тип доменной модели.
...
Рейтинг: 0 / 0
13.11.2012, 23:49
    #38037203
МСУ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtor, только пьяный архитектор может шунтировать классы подобными костылями.
((INHibernateProxy)proxy).HibernateLazyInitializer.PersistentClass тебе в помощь.
...
Рейтинг: 0 / 0
14.11.2012, 00:01
    #38037209
SolYUtor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
МСУ,

отличии от твоего это 100% рабочий способ, не говоря уже о простоте. Ибо ((INHibernateProxy)proxy).HibernateLazyInitializer.PersistentClass будеть падать с InvalidCastException на свежесозданных Transient сущностях.
...
Рейтинг: 0 / 0
14.11.2012, 00:21
    #38037222
МСУ
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtor, то, что этот гавнокод работает еще не означает, что подобный подход правильный. Недокументированные приемы - зло. Кстати, туда же: HibernateLazyInitializer.GetImplementation()
...
Рейтинг: 0 / 0
14.11.2012, 00:23
    #38037226
Где-то в степи
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtor,
Немного офтопа, а как Ваше мнение, на сегодняшний момент, можно бы было уйти от прокси, а маркировать реальные объекты, для кеширования, обновления из кеша и тд,?, поднялось бы быстродействие, была бы более изящное решение?
...
Рейтинг: 0 / 0
14.11.2012, 09:14
    #38037384
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtorДело в том, что NHibernate делает динамические прокси классы, которые наследуют от классов доменной модели. Если вызвать на таком класси GetType(), то это будет не ваш класс, а класс с названием ProxyМногобукв.
Ну собственно это в книжке и написано.

SolYUtorПри этом внутри этого прокси-класса есть ссылка на настоящий класс.
Возможно. Но откуда методу GetUnproxiedType() об этом знать и как он вызовет GetType() у этого настоящего класса, если его реализация, описанная в книжке есть this.GetType()?

SolYUtorЧтобы сравнить реальные типы и нужен GetUnproxiedType, только он должен быть с модификатором Protected или public. Волшество в том, что при таком раскладе проки-тип перенапривит вызов реальному типу, и вернёт его тип. Но для private методов такое волшебство не работает, т.к. они не переопределятеся прокси-типом. Поэтому private GetUnproxiedType() вернёт ProxyМногобукв, а public или protected GetUnproxiedType() вернёт тип доменной модели.
Вот тут у меня почему-то стойкое убеждение что реализация Object.GetType() вернет именно "Точный тип текущего экземпляра в среде выполнения", а не что-то иное, т.е. в каком бы из родительских для прокси-класса метод описан не был, все равно будет возвращен именно тот тип, который создавался средой выполнения, а именно ПроксиЧегоТо. Правильно ли я думаю?
...
Рейтинг: 0 / 0
14.11.2012, 09:30
    #38037397
Алексей К
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
МСУSolYUtor, только пьяный архитектор может шунтировать классы подобными костылями.
((INHibernateProxy)proxy).HibernateLazyInitializer.PersistentClass тебе в помощь.Ужас какой. :-) Для сравнения, в EF это решается, на мой взгляд, более элегантно:
Код: c#
1.
var realEntityType = ObjectContext.GetObjectType(myEntity.GetType())
...
Рейтинг: 0 / 0
14.11.2012, 10:38
    #38037483
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtor,

Сейчас для меня иерархия классов, строящаяся на основе описанного в книжке базового типа при работе NH представляется вот так:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
using System;

namespace ConsoleApplication22
{
    class Program
    {
        static void Main(string[] args)
        {
            var v = new Proxy();
            var v2 = new Proxy();
            v.Equals(v2);
            Console.ReadKey();
        }
    }

    abstract class Entity
    {
        private Type GetUnproxiedType()
        { return GetType(); }

        public override bool Equals(object o)
        {
            var other = o as Entity;

            Console.WriteLine(other.GetType());
            Console.WriteLine(other.GetUnproxiedType());

            return true;
        }
    }

    class Product : Entity
    {
    }

    class Proxy : Product
    {
    }
}



И я не понимаю, почему private Type GetUnproxiedType() { return GetType(); } должен возвращать тип, в котором он описан, и уж тем более именно тип предка прокси, а не сам тип прокси?
...
Рейтинг: 0 / 0
14.11.2012, 11:06
    #38037524
SolYUtor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
Lamo2012И я не понимаю, почему private Type GetUnproxiedType() { return GetType(); } должен возвращать тип, в котором он описан, и уж тем более именно тип предка прокси, а не сам тип прокси?
Вы невнимательно читали. Есть класса А, и хибер вернул вам ПроксиА. ПроксиА содержит ссылку на А, и GetUproxiedType вызовет GetUnproxiedType на экземпляре А, но не ПроксиА, при условии, что GetUnproxiedType public | protected virtual. Просто GetType вызовется на экземпляре ПроксиА, и вернёт тип прокси.
...
Рейтинг: 0 / 0
14.11.2012, 11:10
    #38037535
SolYUtor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
Lamo2012, аналогия грубая, но принцип такой.

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class A
{
    public virtual Type GetUnproxiedType()
    {
       return GetType();
    }
}

public class ProxyA
{
    public ProxyA(A a)
    {
        this.a = a;
    }
    public virtual Type GetUnproxiedType()
    {
        return a.GetUproxiedType();
    }
}
...
Рейтинг: 0 / 0
14.11.2012, 11:12
    #38037539
SolYUtor
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
Забыл наследования добавить.
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
public class A
{
    public virtual Type GetUnproxiedType()
    {
       return GetType();
    }
}

public class ProxyA : A
{
    public ProxyA(A a)
    {
        this.a = a;
    }
    public virtual Type GetUnproxiedType()
    {
        return a.GetUproxiedType();
    }
}
...
Рейтинг: 0 / 0
14.11.2012, 11:21
    #38037559
Lamo2012
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Вызов GetType()
SolYUtor,

Спасибо! Ваши ответы как всегда на высоте!

Я тут тоже нашел аналогичный ответ на этот вопрос.

Суть вот в чем
"I actually went ahead and wrote to the author of the book about this code. It turns out this is due to how the proxy wrapping works. Here is his response:

"If you don't understand how the proxy frameworks work, the idea can seem magical.

When NHibernate returns a proxy for the purposes of lazy loading, it returns a proxy instance inherited from the actual type. There are a few members we can access without forcing a load from the database. Among these are proxy's Id property or field, GetType(), and in some circumstances Equals() and GetHashCode(). Accessing any other member will force a load from the database.

When that happens, the proxy creates an internal instance. So, for example, a lazy loaded instance of Customer (CustomerProxy102987098721340978), when loaded, will internally create a new Customer instance with all of the data from the database. The proxy then does something like this:
Код: c#
1.
2.
3.
4.
5.
6.
7.
public overrides string Name 
{ 
    get { 
       return _loadedInstance.Name; 
    } 
    set { _loadedInstance.Name = value; } 
}



Incidentally, it's this overriding that requires everything to be virtual on entities that allow lazy loaded.

So, all calls to the Name property on the proxy are relayed to the internal Customer instance that has the actual data.

GetUnproxiedType() takes advantage of this. A simple call to GetType() on the proxy will return typeof(CustomerProxy02139487509812340); A call to GetUnproxiedType() will be relayed to the internal customer instance, and the internal customer instance will return typeof(Customer).""

Спасибо всем, кто откликнулся.
...
Рейтинг: 0 / 0
Форумы / WinForms, .Net Framework [игнор отключен] [закрыт для гостей] / Вызов GetType() / 14 сообщений из 14, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]