Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.56/25: Рейтинг темы: голосов - 25, средняя оценка - 4.56
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614

Перегрузка операторов в обобщенном классе. Сложение, вычитание типов T

07.09.2017, 20:58. Показов 4848. Ответов 15
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Потихоньку изучаю C#. Тут решил написать обобщенный класс, который тип T представляет из себя любой тип, связанный с числами. Можно ли его как-нибудь до этого ограничить.
Проблема в том, что в моем обобщенном классе есть перегрузка операторов +, - и тд. Соответственно внутри методов перегрузки, мне нужно суммировать, вычитать объекты типа T, что компилятор не дает сделать, так как не знает о T нихрена...ох как же я привык к C++...

Как такое реализовывается?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
07.09.2017, 20:58
Ответы с готовыми решениями:

Перегрузка операторов в обобщенном классе
Всем привет. Вопрос такой: "Можно ли в обобщённом классе как-нибудь перегрузить операторы *, -, +"? У меня сейчас выдаёт...

Перегрузка операторов +(сложение), -(вычитание), *(умножение)
Для этого нужно создавать класс/ы и оперировать с ним/и? Т.е. перегрузка операторов это тема из раздела ООП? Или можно обойтись...

Конфликт двух типов в обобщённом классе
Столкнулся с проблемой и не могу решить как её лучше решить. Показываю на примере. Есть некий интерфейс ///...

15
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
07.09.2017, 21:32
Ограничить получится в лучшем случае интерфейсом
C#
1
2
3
4
5
6
7
8
9
10
11
interface INumber {
    int Value { get; }
}
 
struct MyNumber : INumber {
    public int Value { get; set; }
}
 
int Add<T>(T l, T r) where T : INumber {
    return l.Value + r.Value;
}
Либо рефлексией (только перегруженные операторы, не подойдет для встроенных примитивных типов)
C#
1
2
3
public static T Add<T>(T x, T y) {
    return (T)typeof(T).GetMethod("op_Addition", BindingFlags.Static | BindingFlags.Public).Invoke(null, new object[] { x, y });
}
Либо через dynamic
C#
1
2
3
public static T Add<T>(T x, T y) {
    return (T)Convert.ChangeType((dynamic)x + (dynamic)y, typeof(T));
}
3
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
07.09.2017, 21:40  [ТС]
jr_,
Цитата Сообщение от jr_ Посмотреть сообщение
Ограничить получится в лучшем случае интерфейсом
C#
1
2
3
4
5
6
7
8
9
10
11
interface INumber {
    int Value { get; }
}
 
struct MyNumber : INumber {
    public int Value { get; set; }
}
 
int Add<T>(T l, T r) where T : INumber {
    return l.Value + r.Value;
}
Здесь Вы конкретно указываете, что значение имеет тип int. Тоесть Вы и складываете int по сути. Какая-то бесполезная обертка в данном случае, я думаю.

Цитата Сообщение от jr_ Посмотреть сообщение
Либо рефлексией (только перегруженные операторы, не подойдет для встроенных примитивных типов)
Ну мне как раз и хотелось для встроенных типов использовать перегрузку, только встроенный тип передаваться будет через T.

Грубо говоря, есть класс Matrix<T>, который предоставляет возможность работы с матрицами из линейной алгебры. Мне бы хотелось, чтобы этот класс был обобщенный для таких типов как int, double, float, мнимые числа и тд. И еще, конечно же, хотелось бы перегрузить оператор +(что у меня получилось), и внутри него, по законам линейной алгебры, складывать матрицы. Только вот сложение двух T не получается, так как компилятор не знает о T.

Я так понял, такое сделать нереально на C#? И мне придется просто перегрузить оператор + для множество известных типов и все?
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
07.09.2017, 21:44
тогда вариант с dynamic будет самым оптимальным
1
Каждому свое
 Аватар для Bretbas
533 / 219 / 81
Регистрация: 05.08.2013
Сообщений: 1,614
07.09.2017, 21:46  [ТС]
jr_, я пока до dynamic не дошел еще свое изучение C#. Но уже предполагаю, что этот вариант с dynamic будет долгий...
Ладно, я попробую. Спасибо
0
 Аватар для AnotherDev
20 / 20 / 13
Регистрация: 29.08.2017
Сообщений: 89
08.09.2017, 00:52
Вот тут есть ещё способ:
Перегрузка операторов в обобщенном классе
1
Эксперт .NET
 Аватар для Usaga
14299 / 9384 / 1353
Регистрация: 21.01.2016
Сообщений: 35,380
08.09.2017, 07:02
Цитата Сообщение от Bretbas Посмотреть сообщение
Как такое реализовывается?
По-хорошему: никак. В C# генерики очень ограниченны в своих возможностях. Тут вам или интерфейсы помогут или рефлексия. Костыли, в общем.
1
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
08.09.2017, 07:49
еще прикинул вариант, вспомнив про эту тему Inside CIL (прогни NET ну хоть чуть чуть)
инлайнить IL я не умею, поэтому воспользовался геном.
по идее, самый предпочтительный и быстрый вариант.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Number<T> where T : struct {
    private T _value;
    private static DynamicMethod _add = GenAdd();
 
    public Number(T value) {
        _value = value;
    }
 
    private static DynamicMethod GenAdd() {
        var method = new DynamicMethod("__Add", typeof(T), new[] { typeof(T), typeof(T) });
        var gen = method.GetILGenerator();
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(OpCodes.Add);
        gen.Emit(OpCodes.Ret);
        return method;
    }
 
    public static Number<T> operator+(Number<T> left, Number<T> right) {
        return new Number<T>((T)_add.Invoke(null, new object[] { left._value, right._value }));
    }
}
3
Эксперт .NET
 Аватар для Usaga
14299 / 9384 / 1353
Регистрация: 21.01.2016
Сообщений: 35,380
08.09.2017, 08:05
jr_, Хоть так и можно, но по своей сути это - некая разновидность низкоуровнего читерства.
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
08.09.2017, 08:22
Usaga, разумеется. врядли найдется такой язык, который бы удовлетворил абсолютно любую потребность. Рано или поздно найдется очень нетривиальная задача. К тому же использование IL еще не такой грязный хак как манипулирование, например, внутренними недокументированными структурами и методами
0
171 / 92 / 71
Регистрация: 10.05.2014
Сообщений: 432
19.05.2018, 16:19
jr_, то есть, если я правильно понял, допустим, если мне необходимо сложить два интовых числа по этому алгоритму, то надо добавить

C#
1
public static Number<T> Method<T>(Number<T> val1, Number<T> val2) where T : struct => val2 + val1;
и в мейне вызывать
C#
1
2
3
4
5
static void Main(string[] args)
{
    Console.WriteLine(Method(new Number<int>(10), new Number<int>(5)));
    Console.ReadLine();
}
Или я что-то не так понял?

И если я понял правильно, то как тогда сделать другие математические операции - умножение, деление, вычитание
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
19.05.2018, 16:20
Это к какому посту относится ?
0
171 / 92 / 71
Регистрация: 10.05.2014
Сообщений: 432
19.05.2018, 16:27
jr_, к этому.

В теории я ведь правильно понимаю, что умножение, к примеру, делается так:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static DynamicMethod GenMultyply()
{
    var method = new DynamicMethod("__Multyply", typeof(T), new[] { typeof(T), typeof(T) });
    var gen = method.GetILGenerator();
    gen.Emit(OpCodes.Ldarg_0);
    gen.Emit(OpCodes.Ldarg_1);
    gen.Emit(OpCodes.Mul);
    gen.Emit(OpCodes.Ret);
    return method;
}
 
public static Number<T> operator *(Number<T> left, Number<T> right)
{
    return new Number<T>((T)_multyply.Invoke(null, new object[] { left._value, right._value }));
}
0
139 / 139 / 53
Регистрация: 14.06.2016
Сообщений: 467
19.05.2018, 16:32
да, так подойдет, при условии что T value определена операция умножения
0
171 / 92 / 71
Регистрация: 10.05.2014
Сообщений: 432
19.05.2018, 17:08
Сделал вот так, может кому пригодится

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
49
50
51
internal class Number<T> where T : struct
{
    public Number(T value) => _value = value;
 
    private readonly T _value;
    private static DynamicMethod _add = GenOperation("__Add");
    private static DynamicMethod _multyply = GenOperation("__Multyply");
    private static DynamicMethod _subtraction = GenOperation("__Subtraction");
    private static DynamicMethod _division = GenOperation("__Division");
 
    private static DynamicMethod GenOperation(string operation)
    {
        var method = new DynamicMethod(operation, typeof(T), new[] { typeof(T), typeof(T) });
        ILGenerator gen = method.GetILGenerator();
        gen.Emit(OpCodes.Ldarg_0);
        gen.Emit(OpCodes.Ldarg_1);
        gen.Emit(
            object.Equals(operation, "__Subtraction") ? OpCodes.Sub :
                object.Equals(operation, "__Division")    ? OpCodes.Div :
                    object.Equals(operation, "__Multyply")    ? OpCodes.Mul :
                        object.Equals(operation, "__Add")    ? OpCodes.Add : default(OpCode)
                );        
        gen.Emit(OpCodes.Ret);
        return method;
    }
 
    public static Number<T> operator - (Number<T> left, Number<T> right) => 
        new Number<T>((T)_subtraction.Invoke(null, new object[] { left._value, right._value }));
 
    public static Number<T> operator * (Number<T> left, Number<T> right) => 
        new Number<T>((T)_multyply.Invoke(null, new object[] { left._value, right._value }));
 
    public static Number<T> operator + (Number<T> left, Number<T> right) => 
        new Number<T>((T)_add.Invoke(null, new object[] { left._value, right._value }));
 
    public static Number<T> operator / (Number<T> left, Number<T> right) =>
        new Number<T>((T)_division.Invoke(null, new object[] { left._value, right._value }));
}
 
 
public static Number<T> MethodAdd<T>(Number<T> val1, Number<T> val2) 
    where T : struct => val2 + val1;
 
public static Number<T> MethodMul<T>(Number<T> val1, Number<T> val2)
    where T : struct => val2 * val1;
 
public static Number<T> MethodSub<T>(Number<T> val1, Number<T> val2)
    where T : struct => val2 - val1;
 
public static Number<T> MethodDiv<T>(Number<T> val1, Number<T> val2)
    where T : struct => val2 / val1;
1
171 / 92 / 71
Регистрация: 10.05.2014
Сообщений: 432
25.03.2019, 20:55
jr_, а не подскажешь как подружить такой метод ещё и с типами с плавающей запятой, а не только с целочисленными типами. А-то при, к примеру, сложении 3х double'в возникает проблема с рефлексией, которую я прям хз как обойти.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
25.03.2019, 20:55
Помогаю со студенческими работами здесь

Сложение и вычитание матриц. Перегрузка операторов.
Добрый день)) посмотрите пожалуйста на мой код и помогите, если не сложно) #include &lt;conio.h&gt; #include &lt;iostream&gt; using...

Перегрузка операторов для стандартных типов/Сложение char[] и int
Добрый день. Захотелось узнать, а можно ли написать оператор сложения для char и char? Пробовал так: #include &lt;iostream&gt; ...

Перегрузка операторов в классе
Создал класс ivl, нужно перегрузить операторы приведенные ниже и Dev C++ пишет, что &quot;ivl is not a type&quot;. Код прилагается. class...

Перегрузка операторов в классе
Здравствуйте. Написал класс: template &lt;class T&gt; class LIST { private: T* listP; uint lSize; public:

Перегрузка операторов в классе
Привет всем снова! Пожалуста помотрите на класс, представьте что все нужные заголовки включены. class Point { public: Point(void) :...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Новые блоги и статьи
Как дизайн сайта влияет на конверсию: 7 решений, которые реально повышают заявки
Neotwalker 08.03.2026
Многие до сих пор воспринимают дизайн сайта как “красивую оболочку”. На практике всё иначе: дизайн напрямую влияет на то, оставит человек заявку или уйдёт через несколько секунд. Даже если у вас. . .
Модульная разработка через nuget packages
DevAlt 07.03.2026
Сложившийся в . Net-среде способ разработки чаще всего предполагает монорепозиторий в котором находятся все исходники. При создании нового решения, мы просто добавляем нужные проекты и имеем. . .
Модульный подход на примере F#
DevAlt 06.03.2026
В блоге дяди Боба наткнулся на такое определение: В этой книге («Подход, основанный на вариантах использования») Ивар утверждает, что архитектура программного обеспечения — это структуры,. . .
Управление камерой с помощью скрипта OrbitControls.js на Three.js: Вращение, зум и панорамирование
8Observer8 05.03.2026
Содержание блога Финальная демка в браузере работает на Desktop и мобильных браузерах. Итоговый код: orbit-controls-threejs-js. zip. Сканируйте QR-код на мобильном. Вращайте камеру одним пальцем,. . .
SDL3 для Web (WebAssembly): Синхронизация спрайтов SDL3 и тел Box2D
8Observer8 04.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-sync-physics-sprites-sdl3-c. zip На первой гифке отладочные линии отключены, а на второй включены:. . .
SDL3 для Web (WebAssembly): Идентификация объектов на Box2D v3 - использование userData и событий коллизий
8Observer8 02.03.2026
Содержание блога Финальная демка в браузере. Итоговый код: finish-collision-events-sdl3-c. zip Сканируйте QR-код на мобильном и вы увидите, что появится джойстик для управления главным героем. . . .
Реалии
Hrethgir 01.03.2026
Нет, я не закончил до сих пор симулятор. Эта задача сложнее. Не получилось уйти в плавсостав, но оно и к лучшему, возможно. Точнее получалось - но сварщиком в палубную команду, а это значит, в моём. . .
Ритм жизни
kumehtar 27.02.2026
Иногда приходится жить в ритме, где дел становится всё больше, а вовлечения в происходящее — всё меньше. Плотный график не даёт вниманию закрепиться ни на одном событии. Утро начинается с быстрых,. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru