Здравствуйте, _FRED_, Вы писали:
_FR>Здравствуйте, Пельмешко, Вы писали:
П>>Это всё из-за того, что чтобы вызвать интерфейсный метод, структуру пришлось бы боксить, что неприемлимо в generic-коде.
_FR>Гхм: почему не приемлемо? Мне казалось, что именно так вызываются методы интерфейсов, реализованные в структуре явно. Разве нет?
Потомушта
static T Baz<T>(T t) where T : IFoo
{
t.Bar();
return t;
}
Просто этот код должен иметь
такую же семантику, как если бы вместо T был конкретный тип.
Если в код простой текстовой заменой в качестве T подставить Foo:
struct Foo : IFoo
{
int x;
public void Bar() { x++; }
}
То не смотря на то, что Bar() реализует интерфейс, вызов не повлечет за собой боксинга и Bar() может изменить значение локальной переменной t, соответственно generic-код должен обладать точно такое же семантикой. Как именно дергаться будет Bar() для достижения сего эффекта — дело реализации: в случае ref-типов можно смело дёргать через интерфейс, в случае value-типов приходится компилировать специализации кода.
_FR>И, кстати, решарпер, кажется, предупреждает о возможном боксинге при сравнении переменной дженерик-типа без ограничения struct/class c null, тогда как Рихтер утверждал, что такое сравнение нормально переварится джитом и не нужный (заранее известно, что ложный) код попросту не будет скомпилирован — кто прав тут
Не видел таких suggestion'ов решарпера...
Было бы интересно увидеть подобные случаи
Здравствуйте, Пельмешко, Вы писали:
П>Если в код простой текстовой заменой в качестве T подставить Foo:
П>П>struct Foo : IFoo
П>{
П> int x;
П> public void Bar() { x++; }
П>}
П>
П>То не смотря на то, что Bar() реализует интерфейс, вызов не повлечет за собой боксинга и Bar() может изменить значение локальной переменной t, соответственно generic-код должен обладать точно такое же семантикой.
Говоришь, простая текстовая замена?
А если в структуре интерфейс реализован явно (IFoo.Bar)?
Здравствуйте, Пельмешко, Вы писали:
П>>>Это всё из-за того, что чтобы вызвать интерфейсный метод, структуру пришлось бы боксить, что неприемлимо в generic-коде.
_FR>>Гхм: почему не приемлемо? Мне казалось, что именно так вызываются методы интерфейсов, реализованные в структуре явно. Разве нет?
П>Потомушта
П>static T Baz<T>(T t) where T : IFoo
П>{
П> t.Bar();
П> return t;
П>}
П>Просто этот код должен иметь такую же семантику, как если бы вместо T был конкретный тип.
П>Если в код простой текстовой заменой в качестве T подставить Foo:
П>struct Foo : IFoo
П>{
П> int x;
П> public void Bar() { x++; }
П>}
П>То не смотря на то, что Bar() реализует интерфейс, вызов не повлечет за собой боксинга и Bar() может изменить значение локальной переменной t, соответственно generic-код должен обладать точно такое же семантикой. Как именно дергаться будет Bar() для достижения сего эффекта — дело реализации: в случае ref-типов можно смело дёргать через интерфейс, в случае value-типов приходится компилировать специализации кода.
Я говорил про случай явной реализации структурой метода интерфейса. В случае "простой текстовой заменой" без боксинга точно будет не обойтись
Что значит "компилировать специализации кода"?
Здравствуйте, Аноним, Вы писали:
А>Здравствуйте, Пельмешко, Вы писали:
П>>Если в код простой текстовой заменой в качестве T подставить Foo:
П>>П>>struct Foo : IFoo
П>>{
П>> int x;
П>> public void Bar() { x++; }
П>>}
П>>
П>>То не смотря на то, что Bar() реализует интерфейс, вызов не повлечет за собой боксинга и Bar() может изменить значение локальной переменной t, соответственно generic-код должен обладать точно такое же семантикой.
А>Говоришь, простая текстовая замена?
А>А если в структуре интерфейс реализован явно (IFoo.Bar)?
Да, я ошибался... в случае явной реализации семантика изменяется...
Грустно это всё, но иначе и не может быть...
Здравствуйте, _FRED_, Вы писали:
_FR>Что значит "компилировать специализации кода"?
Я про то, что JIT в CLR генерирует n версий нативного кода (их я и назвал "специализациями") при подстановке n различных value-типов в качестве T в каком-нибудь generic-методе + одна нативная версия для всех ref-типов. К сожалению, в случае value-типов даже нельзя переиспользовать код нативный код для Baz<int>() в качестве кода Baz<uint>(), не смотря на то, что структуры идентичного размера и вообще мягко говоря очень похожи
Насколько я знаю, в Mono вообще только недавно научились переиспользовать один код для всех ref-типов....