Но у меня несколько другой вопрос.
Можно ли перевеси ошибку "Compiler Error CS0309", о несоответсвии генергик-типа заданному ограничению, из ошибки времени компиляции в ошибку времени выполнения.
Т.е., допустим, я во время выполнения сам проверю реальный тип переменных на соответствие нужным ограничениям (оператор is) и в зависимости от реального типа вызову тот или иной метод с параметрами генерик-типов, удовлетворяющих генерик-ограничением этих методов.
Пример
using System;
using System.Collections.Generic;
using System.Text;
namespace WindowsApplication1
{
public interface Imod
{
void mod();
}
public class MyClass
{
public void func<T>(T a)
{
if (a is Imod)
{ f1<T>(a); } //*else { f2<T>(a); }
}
private void f1<T>(T a) where T : Imod
{
a.mod();
}
private void f2<T>(T a)
{
}
}
}
Строка, помеченная "*" вызывает ошибк времени компиляции
The type 'T' must be convertible to 'WindowsApplication1.Imod' in order to use it as parameter 'T'
Соотвственно один из двух вариантов вопроса: 1. Можно ли как-то конверитровать неограниченный генерик тип в ограниченный для использования в методах требующих ограниченный генерик-тип? Как сделать его "must be convertible"? 2. Как вызывать методы объектов, имеющих, неограниченный генерик тип, зная во время выполнения, конкретный тип? Ни чего кроме варианат использования рефлексии и member.invoke() в голову не приходит — но это не эффективно с точки зрения скорости выполнения (нужна высокая скорость)!
Есл ничего нормальным путём из этого сделать нельзя, то тогда встаёт вопрос о реальной пользы использования generic типо и generic ограничений — если возникает такая проблема при переходе от более обобщённых типов к более ограниченным.
Всего лишь хочу в зависимости от реального типа применять к переменной генерик-типа тот или иной алгоритм (в зависимости от того, оддерживает ли этот тип некоторые методы или не поддерживает) — но получается, что это нормальным путём невозможно
Решение зависит от конкретной ситуации, насколько сильное ограничение и какими методами достигается. Может не совсем понял пример, но в вашем случае же можно обойтись простым приведением:
Здравствуйте, darklight, Вы писали:
D>2. Как вызывать методы объектов, имеющих, неограниченный генерик тип, зная во время выполнения, конкретный тип? Ни чего кроме варианат использования рефлексии и member.invoke() в голову не приходит — но это не эффективно с точки зрения скорости выполнения (нужна высокая скорость)!
Пожалуй, это единственный выход.
D>Есл ничего нормальным путём из этого сделать нельзя, то тогда встаёт вопрос о реальной пользы использования generic типо и generic ограничений — если возникает такая проблема при переходе от более обобщённых типов к более ограниченным.
Не нужно смешивать в одну кучу runtime и compile-time полиморфизм. Их одновременное использование в данном случае легким не будет.
Здравствуйте, darklight, Вы писали:
D>Соотвственно один из двух вариантов вопроса: D>1. Можно ли как-то конверитровать неограниченный генерик тип в ограниченный для использования в методах требующих ограниченный генерик-тип? Как сделать его "must be convertible"?
К сожалению, это недостаток системы типов .NET.
Обойти это ограничение можно только с помощью рефлекшна.
D>2. Как вызывать методы объектов, имеющих, неограниченный генерик тип, зная во время выполнения, конкретный тип? Ни чего кроме варианат использования рефлексии и member.invoke() в голову не приходит — но это не эффективно с точки зрения скорости выполнения (нужна высокая скорость)!
Можно привести объект к соответствующему интерфейсу, но это вызовет упаковку для value-типов.
Здравствуйте, Vovstehn, Вы писали:
V>Здравствуйте, darklight, Вы писали:
D>> skipped
V>Решение зависит от конкретной ситуации, насколько сильное ограничение и какими методами достигается. Может не совсем понял пример, но в вашем случае же можно обойтись простым приведением:
V>
V>f1<Imod>((Imod)a);
V>
Да! Действительно это работает как же я с разу не догадался спасибо
D>Да! Действительно это работает как же я с разу не догадался спасибо
Раз этот вариант подходит, то вообще не ясно, зачем было делать этот метод generic. Можно было объявить аргумент как Imod.
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, darklight, Вы писали:
D>>Соотвственно один из двух вариантов вопроса: D>>1. Можно ли как-то конверитровать неограниченный генерик тип в ограниченный для использования в методах требующих ограниченный генерик-тип? Как сделать его "must be convertible"? N>К сожалению, это недостаток системы типов .NET. N>Обойти это ограничение можно только с помощью рефлекшна.
D>>2. Как вызывать методы объектов, имеющих, неограниченный генерик тип, зная во время выполнения, конкретный тип? Ни чего кроме варианат использования рефлексии и member.invoke() в голову не приходит — но это не эффективно с точки зрения скорости выполнения (нужна высокая скорость)! N>Можно привести объект к соответствующему интерфейсу, но это вызовет упаковку для value-типов.
Вот с привидением к определённому интерфейсу у меня и вышла загвозка.
Спасибо Vovstehn полказал как правильно
Упаковка это меньшая из зол, чем рефлексия, и так понятно, что типами-значений не всё так хорошо будет, как хотелось бы, ну у меня как раз ссылочные типы требую отдельной обработки, а типы-значений я пока не планирую обрабатывать в данном алгоритме, значит и упаковки тоже не будет
В общем решение пока найдено — всем спасибо
вот такой вот пример получился — проверил — работает
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsApplication1
{
public interface Imod
{
void mod();
}
public class aClass : Imod
{
public void mod()
{
throw new System.Exception("mod!");
}
}
public class bClass
{
}
public class MyClass
{
public void func<T>(T a)
{
if (a is Imod)
{ f1<Imod>((Imod)a); } //*else { f2<T>(a); }
}
private void f1<T>(T a) where T : Imod
{
a.mod();
}
private void f2<T>(T a)
{
throw new System.Exception("mod unsupported");
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
aClass a = new aClass();
bClass b = new bClass();
MyClass c = new MyClass();
//c.func<aClass>(a);
c.func<bClass>(b);
}
}
}
Здравствуйте, Mab, Вы писали:
Mab>Здравствуйте, darklight, Вы писали:
V>>>
V>>>f1<Imod>((Imod)a);
V>>>
D>>Да! Действительно это работает как же я с разу не догадался спасибо Mab>Раз этот вариант подходит, то вообще не ясно, зачем было делать этот метод generic. Можно было объявить аргумент как Imod.
В точку! Простоя запутался в этих генериках и привидениях типа.
Откажусь от генерика в определении метода, оставлю только приведение типа.
Просто исходный аргумент (переменная a) в реальном коде имеет неограниченный генерик-тип
В общем разобрался, спасибо за подсказки!
Буквально за 10 минут до того, как я прочитал предложенные решения в ответах на мой вопрос — я сам нашёл своё решение — оно конечно менее изящное, но более унивесральное.
А именно — я сделал вот такую вот функцию
public System.Object ToObject<T>(T Val) { return Val; }
И всё — на входе генерик-тип — а на выходе уже System.Object — далее с ним можно делать всё-что угодно (в т.ч. приведение типа через оператор as и проверку типа оператором is — но это уже так к слову добавил, может кому (кто ещё сталкнётся с такой же проблемой) так больше понравится...
Здравствуйте, nikov, Вы писали:
N>Здравствуйте, darklight, Вы писали:
D>>Главное найдено решение из, казалось бы, безвыходной генерик-ситуации
N>А что делать, если у тебя в констрейнте 2 интерфейса?
После приведения к типу System.Object уже не важно сколько там ограничений. И вообще, эти генерик-ограничения это фикция — лучше всё проверять через оператор is во время выполнения (это про generic), т.к. реальный тип известен только вов реям выполнения, а на стадии компиляции неограниченные generic-типы всеьма ограничены в применения без доп. преобразований времени выполнения (аля рассмотренные выше), а ограниченные generic-типы очень ограничены в своём применении вместе с уже разработанными библиотеками (в т.ч. платформенными), т.к. эти ограничения н удастся хорошо сочетать с стандартными типами.
Здравствуйте, darklight, Вы писали:
D>Здравствуйте, nikov, Вы писали:
N>>Здравствуйте, darklight, Вы писали:
D>>>Главное найдено решение из, казалось бы, безвыходной генерик-ситуации
N>>А что делать, если у тебя в констрейнте 2 интерфейса?
D>После приведения к типу System.Object уже не важно сколько там ограничений. И вообще, эти генерик-ограничения это фикция — лучше всё проверять через оператор is во время выполнения (это про generic), т.к. реальный тип известен только вов реям выполнения, а на стадии компиляции неограниченные generic-типы всеьма ограничены в применения без доп. преобразований времени выполнения (аля рассмотренные выше), а ограниченные generic-типы очень ограничены в своём применении вместе с уже разработанными библиотеками (в т.ч. платформенными), т.к. эти ограничения н удастся хорошо сочетать с стандартными типами.
Что я не так делаю? Меня вполне устраивают эти ограничения. И даже в случае с операторе есть обходной путь — смотрите BLToolkit