Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 16.08.12 10:55
Оценка:
Друзья, подскажите, как сделать такое:

Постараюсь объяснить проблему, предельно упрощая ситуацию: одна (внешняя) контора разработала нам библиотеку (сборку) для выполнения некоторой охренительно важной для нас функции (назовем сборку asm.dll, версия 1). Но стандарты в этой области поменялись, и контора выпустила новую версию сборки для выполнения той же самой функции (назовем ее asm.dll, версия 2). Предполагалось, что в "Час X" все разработчики-пользователи библиотеки пересоберут свой софт с новой версией сборки и все чудесным образом заработает по новым стандартам.

Для простоты будем полагать, что внутри сборок что-то вроде такого:

namespace MySpace
{
  public class MyObject
  {
// тут конструкторы всякие
    public string Transform(string s)
    {
// ....
    }
  }
}


Но, как всегда, жизнь внесла свои коррективы. Оказалось, что вместо "Часа Х" будет "Год Х", в течение которого оба подхода должны использоваться совместно. Ну то есть в зависимости от некоторых условий вызывать Transform или из одной, или из другой сборки. То есть прилинковать к своей проге их обе (а скоро будет и третья, а там и четвертая не за горами).

Ну то есть я хочу сделать что-то вроде
MySpace.MyObject t1 = new MySpace.MyObject(); // из первой сборки
MySpace.MyObject t2 = new MySpace.MyObject(); // из второй сборки
string s=...

if (SomeConditionOnS(s))
{
  s = t1.Transform(s);
}
else
{
  s = t2.Transform(s);
}


Понятно, что в таком виде это работать не будет. А как правильно решить данную задачу?
Re: Подскажите, как выбраться из такой ловушки
От: hardcase Пират http://nemerle.org
Дата: 16.08.12 10:56
Оценка: 6 (1)
Здравствуйте, Аноним, Вы писали:
А>Ну то есть я хочу сделать что-то вроде
А>
А>MySpace.MyObject t1 = new MySpace.MyObject(); // из первой сборки
А>MySpace.MyObject t2 = new MySpace.MyObject(); // из второй сборки
А>string s=...

А>if (SomeConditionOnS(s))
А>{
А>  s = t1.Transform(s);
А>}
А>else
А>{
А>  s = t2.Transform(s);
А>}
А>


А>Понятно, что в таком виде это работать не будет. А как правильно решить данную задачу?


extern alias
/* иЗвиНите зА неРовнЫй поЧерК */
Re[2]: Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 16.08.12 11:50
Оценка:
Здравствуйте, hardcase, Вы писали:

А>>Понятно, что в таком виде это работать не будет. А как правильно решить данную задачу?


H>extern alias


Спасибо за ответ. А то я уж было подумал, что придется мутить с динамической загрузкой сборок. То есть хоть какой-то вариант у меня есть.

Но на самом деле дела обстоят значительно хуже. Каждая из сборок содержит несколько десятков классов и порядка сотни методов и, таким образом, весь мой код будет забит if'ами. Хотелось бы поступить проще: инстанцировать в некоторую переменную объект класса либо из одной, либо из другой сборки, типа такого:

SomeType t = ( boolCondition ? new Assembly1::MySpace.MyObject() : new Assembly2::MySpace.MyObject());

А дальше уже совершать все опирации с этим единственным объектом.

Можно ли каким-нибудь хитрым способом определить тип SomeType, чтоб переменной этого типа можно было присваивать объекты MyObject из обеих сборок и вызывать их методы?

PS. Краем уха слышал про "утиную" типизацию в C#. Мне кажется, это именно та ситуация, где такая типизация необходима. Т.е. хотелось бы определить SomeType как класс, реализующий заданный набор методов и чтоб переменной этого класса можно было присвоить объект любого класса, в котором эти методы реализованы. Что-нибудь подобное в C# есть?
Re[3]: Подскажите, как выбраться из такой ловушки
От: dobrik Израиль  
Дата: 16.08.12 12:30
Оценка:
Здравствуйте, Аноним, Вы писали:

А>Здравствуйте, hardcase, Вы писали:


А>>>Понятно, что в таком виде это работать не будет. А как правильно решить данную задачу?


H>>extern alias


А>Спасибо за ответ. А то я уж было подумал, что придется мутить с динамической загрузкой сборок. То есть хоть какой-то вариант у меня есть.


А>Но на самом деле дела обстоят значительно хуже. Каждая из сборок содержит несколько десятков классов и порядка сотни методов и, таким образом, весь мой код будет забит if'ами. Хотелось бы поступить проще: инстанцировать в некоторую переменную объект класса либо из одной, либо из другой сборки, типа такого:


А>
А>SomeType t = ( boolCondition ? new Assembly1::MySpace.MyObject() : new Assembly2::MySpace.MyObject());
А>

А>А дальше уже совершать все опирации с этим единственным объектом.

А>Можно ли каким-нибудь хитрым способом определить тип SomeType, чтоб переменной этого типа можно было присваивать объекты MyObject из обеих сборок и вызывать их методы?


А>PS. Краем уха слышал про "утиную" типизацию в C#. Мне кажется, это именно та ситуация, где такая типизация необходима. Т.е. хотелось бы определить SomeType как класс, реализующий заданный набор методов и чтоб переменной этого класса можно было присвоить объект любого класса, в котором эти методы реализованы. Что-нибудь подобное в C# есть?


public T GenerateProxy<T>()
{
return (T)Activator.CreateInstance(typeof(T));
}
dobrik
Re[2]: Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 16.08.12 13:08
Оценка:
Здравствуйте, hardcase, Вы писали:

H>extern alias


Кажется, рано обрадовался. При построении проекта получаю следующее сообщение:

Primary reference "myasm, Version=2.0.199.13, Culture=neutral, PublicKeyToken=8283b45d91d69b7a" Resolved file path is "libs\new\myasm.dll".
Reference found at search path location "{HintPathFromItem}".
There was a conflict between "myasm, Version=2.0.199.13, Culture=neutral, PublicKeyToken=8283b45d91d69b7a" and
"myasm, Version=2.0.160.14, Culture=neutral, PublicKeyToken=8283b45d91d69b7a".
C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : warning MSB3243: No way to resolve conflict between "myasm, Version=2.0.199.13, Culture=neutral, PublicKeyToken=8283b45d91d69b7a"
and "myasm, Version=2.0.160.14, Culture=neutral, PublicKeyToken=8283b45d91d69b7a".
Choosing "myasm, Version=2.0.199.13, Culture=neutral, PublicKeyToken=8283b45d91d69b7a" arbitrarily.
Consider app.config remapping of assembly "myasm, Culture=neutral, PublicKeyToken=8283b45d91d69b7a" from Version "2.0.160.14" [libs\old\myasmold.dll] to Version "2.0.199.13" [libs\new\myasm.dll] to solve conflict and get rid of warning.
C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : warning MSB3247: Found conflicts between different versions of the same dependent assembly.
Done executing task "ResolveAssemblyReference".


Правильно ли я понимаю, что студия выкинула старую сборку, заменив все ссылки на нее ссылками на новую сборку? Если да, то как все-таки работать с двумя версиями сборки в одном проекте?
Re: Подскажите, как выбраться из такой ловушки
От: koodeer  
Дата: 16.08.12 13:13
Оценка:
Здравствуйте, Аноним, Вы писали:

А> назовем сборку asm.dll, версия 1

А> назовем ее asm.dll, версия 2

Правильно ли я понимаю, что типы и члены в сборках одинаковые? Отличается лишь внутренняя реализация и номер версии?
Тогда достаточно указать в манифесте, что приложение должно использовать новую версию сборки. Без перекомпиляции. Не?
Re[2]: Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 16.08.12 13:35
Оценка:
Здравствуйте, koodeer, Вы писали:

K>Правильно ли я понимаю, что типы и члены в сборках одинаковые? Отличается лишь внутренняя реализация и номер версии?

K>Тогда достаточно указать в манифесте, что приложение должно использовать новую версию сборки. Без перекомпиляции. Не?

Все гораздо хуже. В новой сборке, естественно, членов и типов больше, но это в данном случае неважно. На самом деле сборки — это интерфейс к специализированному удаленному серверу. Версии сервера поменялась и поменялись протоколы доступа, поэтому обратной совместимости нет. Новая сборка не может работать со старым сервером — в коде выскакивает исключение. А мне нужно работать с обоими серверами.
Re[3]: Подскажите, как выбраться из такой ловушки
От: Nikolay_P_I  
Дата: 17.08.12 04:44
Оценка:
Здравствуйте, Аноним, Вы писали:

K>>Правильно ли я понимаю, что типы и члены в сборках одинаковые? Отличается лишь внутренняя реализация и номер версии?

K>>Тогда достаточно указать в манифесте, что приложение должно использовать новую версию сборки. Без перекомпиляции. Не?

А>Все гораздо хуже. В новой сборке, естественно, членов и типов больше, но это в данном случае неважно. На самом деле сборки — это интерфейс к специализированному удаленному серверу. Версии сервера поменялась и поменялись протоколы доступа, поэтому обратной совместимости нет. Новая сборка не может работать со старым сервером — в коде выскакивает исключение. А мне нужно работать с обоими серверами.


Не понял.

1) Если код работы (даже не интерфейс) у в1 и в2 одинаковый — просто пихаете их в \subdir1\asm.dll и \subdir2\asm.dll, а в .exe.config ставите probingpath на нужную поддиректорию.

2) Если код отличается или одновременно надо работать с обоими — делайте свой движок и работайте уже с ним. Сам движок пускать в другом домене, процессе, сервисе — как нравится.

3) Ну и external alias уже говорили.
Re[4]: Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 17.08.12 09:22
Оценка:
Здравствуйте, Nikolay_P_I, Вы писали:

N_P>1) Если код работы (даже не интерфейс) у в1 и в2 одинаковый — просто пихаете их в \subdir1\asm.dll и \subdir2\asm.dll, а в .exe.config ставите probingpath на нужную поддиректорию.

Поясните, что такое "код работы"?
Есть две dll-ки (два файла), которые являются различными версиями одной и той же сборки:

"myasm, Version=2.0.199.13, Culture=neutral, PublicKeyToken=8283b45d91d69b7a"
"myasm, Version=2.0.160.14, Culture=neutral, PublicKeyToken=8283b45d91d69b7a"

Унутре у них классы, у классов — методы, у более новой, понятно, набор классов шире и методов больше. Общие для двух сборок методы идентичны по сигнатуре (т.е. перечню и типам аргументов и возвращаемому значению), все пространства имен также совпадают. Сделано это было специально — изначально предполагалось разработчиком этих библиотек, что "новая" просто заменит "старую". Но жизнь внесла свои коррективы и возникла необходимость работать одновременно с обеими.

N_P>2) Если код отличается или одновременно надо работать с обоими — делайте свой движок и работайте уже с ним. Сам движок пускать в другом домене, процессе, сервисе — как нравится.


Да, надо работать с обеими сборками одновременно. Сценарий работы такой: Инстанцируем класс из "новой" dll-ки, куда добавили новую функцию, возвращающую логическое значение для переданных ей данных — "моё/не моё". Вызываем эту функцию, если сказала "моё", продолжаем работать с инстанцированным объектом из новой dll-ки и вызываем его методы. Если сказала "не мое", должны инстанцировать точно такой же (с тем же именем) объект из "старой" dll-ки и все методы (те же самые) вызывать для этого объекта.

Поясните ваши слова "делайте свой движок и работайте уже с ним". Просто так подлинковать обе dll-ки в проект и выбирать нужную для вызова кода через extern alias не получится? Я пытался сделать именно так (добавил ссылки на обе сборки в проект, задал для каждой из сборок свой алиас), но получаю при билде проекта сообщение, что имеется конфликт версий и все ссылки на одну из сборок "перекидываются" на другую:

Consider app.config remapping of assembly "myasm, Culture=neutral, PublicKeyToken=8283b45d91d69b7a" from Version "2.0.160.14" [libs\old\myasmold.dll] to Version "2.0.199.13" [libs\new\myasm.dll] to solve conflict and get rid of warning.
C:\Windows\Microsoft.NET\Framework\v3.5\Microsoft.Common.targets : warning MSB3247: Found conflicts between different versions of the same dependent assembly.


Правильно ли я понимаю, что без "плясок с бубном" заставить обе dll-ки работать в одном экзешнике одновременно невозможно? Насколько сложны эти "пляски"? Что надо сделать?

N_P>3) Ну и external alias уже говорили.

Оказывается, это далеко не самое главное.
Re: Подскажите, как выбраться из такой ловушки
От: HowardLovekraft  
Дата: 17.08.12 10:03
Оценка:
Здравствуйте, Аноним, Вы писали:

А>skipped

А код, работающий с разными версиями сборок, будет одинаковым?
Или все-таки возможна ситуация, когда будет, например, так:
if (SomeConditionOnS(s))
{
  s = t1.Transform(s);
}
else
{
  s1 = t2.Transform1(s);
  s2 = t2.Transform2(s);
  s = s1 + s2;
}
А>

?
Re[2]: Подскажите, как выбраться из такой ловушки
От: Аноним  
Дата: 19.08.12 18:26
Оценка:
Здравствуйте, HowardLovekraft, Вы писали:

HL>Здравствуйте, Аноним, Вы писали:


А>>skipped

HL>А код, работающий с разными версиями сборок, будет одинаковым?
HL>Или все-таки возможна ситуация, когда будет, например, так:

Требуется (при некоторых условиях) вызывать методы из обеих сборок. Во вторую сборку добавили специальный метод, который говорит, какая сборка должна использоваться. Вызовы примерно такие:

string s=...
MySpace.MyObject t2 = new MySpace.MyObject(); // из второй сборки

if (t2.IfAdvancedProcessingRequired(s))
{
  s = t2.Transform(s);
}
else
{
  MySpace.MyObject t1 = new MySpace.MyObject(); // из первой сборки
  s = t1.Transform(s);
}


В остальном две ветки (if-else) идентичны по вызываемым методам объектов из разных сборок.
Re[3]: Подскажите, как выбраться из такой ловушки
От: HowardLovekraft  
Дата: 20.08.12 05:51
Оценка:
Здравствуйте, Аноним, Вы писали:

А>В остальном две ветки (if-else) идентичны по вызываемым методам объектов из разных сборок.

Тогда, может быть, так:
1) создать свой
public interface IMyObject
{
  string Transform(string value);
}

2) создать несколько реализаций IMyObject (одна версия сторонней сборки — одна реализация). Внутри каждой реализации создавать отдельный домен, грузить в него сборку нужной версии, и работать с ней, используя фичи конкретной версии. Если вы не можете влиять на код сторонней сборки, то, возможно, придется дописать еще свою MBR-обертку для каждого варианта MyObject (если он не является MBR);
3) работать с реализациями IMyObject, как с плагинами. Логику "с какой версией сторонней сборки будем работать" поместить в хост для этих плагинов:
public class MyObjectHost
{
  public IMyObject Current
  {
    get
    {
       if (SomeConditionOnS(s))
         return ...; // v 1.0

       return ...; // v 2.0
    }
  }
}

4) ну и в основном коде:
var myObjectHost = new MyObjectHost(/* параметры конструктора */);
var s = "...";

s = myObjectHost.Current.Transform(s);

?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.