Форум программистов, компьютерный форум, киберфорум
Наши страницы
C# для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 14, средняя оценка - 4.86
temcha
28 / 28 / 5
Регистрация: 07.09.2012
Сообщений: 119
#1

Рефлексия: как происходит приведение из object в производные классы и структуры - C#

18.10.2012, 20:36. Просмотров 2084. Ответов 15
Метки нет (Все метки)

Объясните пожалуйста, даю кусок кода из книги Шилдта + 1-2 метода дописанных самостоятельно:
http://www.cyberforum.ru/csharp-beginners/thread2200609.html
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
using System; 
using System.Reflection;
class MyClass
{
    int x;
    int y;
    public MyClass(int i, int j)
    {
        x = i;
        y = j;
    }
    public int Sum()
    {
        return x + y;
    }
    public bool IsBetween(int i)
    {
        if ((x < i) && (i < y)) return true;
        else return false;
    }
 
    public void Set(int a, int b)
    {
        Console.Write("В методе Set (int, int). ");
        x = a;
        y = b;
        Show();
    }
    // Перегрузить метод Set. 
    public void Set(double a, double b)
    {
        Console.Write("В методе Set(double, double). ");
        x = (int)a;
        y = (int)b;
        Show();
    }
    public void Show()
    {
        Console.WriteLine("Значение x: {0}, значение у: {1}", x, y);
    }
    public MyClass Meth(int a)
    {
        MyClass obj = new MyClass(a,a);
        return obj;
    }
 
}
class Program
{
    static void Main()
    {
 
        Type t = typeof(MyClass);
        MyClass reflectOb = new MyClass(10, 20);
        int val;
        MyClass refOb;
 
        Console.WriteLine("Вызов методов, определенных в классе " + t.Name);
        Console.WriteLine();
        MethodInfo[] mi = t.GetMethods();
 
        foreach (var m in mi)
        {
            ParameterInfo[] pi = m.GetParameters();
 
            if (m.Name.CompareTo("Set") == 0 && pi[0].ParameterType == typeof(int))
            {
                object[] args = new object[2];
                args[0] = 9;
                args[1] = 18;
                m.Invoke(reflectOb, args);
            }
            else if (m.Name.CompareTo("Set") == 0 && pi[0].ParameterType == typeof(double))
            {
                object[] args = new object[2];
                args[0] = 1.12;
                args[1] = 23.4;
                m.Invoke(reflectOb, args);
            }
            else if (m.Name.CompareTo("Sum") == 0)
            {
                val = (int)m.Invoke(reflectOb, null);
                Console.WriteLine("Сумма равна " + val);
            }
            else if (m.Name.CompareTo("IsBetween") == 0)
            {
                object[] args = new object[1];
                args[0] = 14;
                if ((bool)m.Invoke(reflectOb, args)) Console.WriteLine("Значение 14 находится между х и у");
            }
            else if (m.Name.CompareTo("Show") == 0)
            {
                m.Invoke(reflectOb, null);
            }
            else if (m.Name.CompareTo("Meth") == 0)
            {
                object[] args = new object[1];
                args[0] = 14;
                refOb=(MyClass)m.Invoke(reflectOb, args);
            }
 
        
        }
    }
}
Вопрос такой:
В методах SUM и Meth возвращается результат типа object ( т.к. метод Invoke() имеет возвращаемый тип object) и приводится к Int и MyClass соответственно. Каким образом в данном случае мы имеем право делать такое приведение? по факту происходит приведение из object в производные классы и структуры. Что то не пойму....
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
18.10.2012, 20:36
Я подобрал для вас темы с готовыми решениями и ответами на вопрос Рефлексия: как происходит приведение из object в производные классы и структуры (C#):

float to double. Как происходит приведение типов?
double x = 1.01F; float y = 1.01F; Console.Write(x); // 1.00999...

Работа с типом Object: как лучше реализовать приведение типов и сравнение
Добрый день Такая задача, есть COM-объект возвращающий по запросу некие...

Приведение int[,] к object[,]
Нужно сделать метод что бы выполнять операции над двумерными массивами любого...

Приведение к первоначальному типу Object
День добрый! Есть два метода, отличаются только первой строкой, подскажите...

Приведение object к пользовательскому типу данных
Добрый день! Как-то не помог мне поиск в решении следующей задачи. Подскажите...

15
andrew_w2k
323 / 323 / 90
Регистрация: 04.03.2010
Сообщений: 648
18.10.2012, 23:09 #2
переменная типа object может принимать значение любого типа данных, так как в C# в конечном итоге все типы наследуются от Object, и приведение здесь вполне уместно
0
temcha
28 / 28 / 5
Регистрация: 07.09.2012
Сообщений: 119
18.10.2012, 23:32  [ТС] #3
Цитата Сообщение от andrew_w2k Посмотреть сообщение
переменная типа object может принимать значение любого типа данных, так как в C# в конечном итоге все типы наследуются от Object, и приведение здесь вполне уместно
да? а попробуй сделать то самое приведение типов. Что у тебя получиться? исключение!
попробуй скомпилить такой код:
using System;
using System.Reflection;
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class MyClass
{
    int x;
    int y;
    public MyClass(int i, int j)
    {
        x = i;
        y = j;
    }
}
class Program
{
    static void Main()
    {
        object A = new object();
 
        MyClass reflectOb = new MyClass(10, 20);
        MyClass refOb = (MyClass) A;
 
        
    }
}
я тут удалил неважные элементы
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
19.10.2012, 01:46 #4
Цитата Сообщение от temcha Посмотреть сообщение
Каким образом в данном случае мы имеем право делать такое приведение?
Когда мы делаем приведение типа, мы говорим компилятору: "Да, мы готовы, что будет выброшено исключение или мы уверены, что исключения никогда не будет".
А уже CLR во время выполнения кода, проверяет, действительно ли такое приведение возможно, и если невозможно - выбрасывает исключение.

В коде из первого поста, так как мы точно знаем тип, который вернет Invoke, то все проходит хорошо. Метод действительно возвратил нужный тип.
Во втором вашем примере, бросается исключение, так как типы не совпадают.
Вроде все логично.

Аналогично. Вас же скорее всего, не смутит такой метод:
C#
1
2
3
4
        public int div(int del)
        {
            return 1000/del;
        }
Компилятор/CLR дает нам его выполнять, не смотря на то, что в него можно передать 0 и все рухнет.
0
temcha
28 / 28 / 5
Регистрация: 07.09.2012
Сообщений: 119
19.10.2012, 02:19  [ТС] #5
хм, сейчас то речь идет не о исключениях. Не нужно приводить примеры с DevideByZeroException. Я говорю о приведении типов. Нельзя приводить из базового в производные классы( что показано на примере object, int). Но при использовании Invoke() все работает. Объясните пожалуйста, каким образом?
0
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
19.10.2012, 09:04 #6
temcha,
C#
1
2
object obj = 5;
int a = (int) obj;
привели int к базовому типу, потом обратно. Что тут исключительного бросается?
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
19.10.2012, 09:25 #7
Цитата Сообщение от temcha Посмотреть сообщение
Не нужно приводить примеры с DevideByZeroException
Почему нет? Я пытался привести аналогию. Можем приводить (делить на ноль), но последствия ложатся на наши плечи.
Цитата Сообщение от temcha Посмотреть сообщение
Нельзя приводить из базового в производные классы( что показано на примере object, int). Но при использовании Invoke() все работает.
Invoke вызывает метод, который вы ему указали - "Meth".
Метод Meth возвращает именно объект типа MyClass, поэтому ошибки не происходит.

Возможно вы не понимаете разницу, что может быть два типа:
- Фактический тип объекта
- Тип переменной, в которой хранится объект.
Эти типы могут не совпадать: фактический тип объекта может быть одним из наследников типа переменной.

Вот и в вашем случае Invoke для "Meth" возвращает переменную типа object, хотя фактический тип объекта - MyClass.
C#
1
2
object A = new object(); //Переменная A: Фактически тип = object, тип переменной = object
MyClass refOb = (MyClass) A; //Переменная refOb: Фактический тип = object, тип переменной = MyClass. Так как MyClass не является наследником object происходит ошибка
C#
1
2
object invokeResult = m.Invoke(reflectOb, args); //Переменная invokeResult: Фактический тип = MyClass, тип переменной = object
refOb=(MyClass)invokeResult;//Переменная refOb: Фактический тип = MyClass, тип переменной = MyClass. Все хорошо, ошибки не происходит
2
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
19.10.2012, 09:34 #8
turbanoff, эм тут уже я не понял. Любой класс неявно наследуется от Object, что значит "Так как MyClass не является наследником object происходит ошибка" о_0
1
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
19.10.2012, 10:33 #9
Действительно, перепутал. Должно быть наоборот:
Так как object не является наследником MyClass происходит ошибка
0
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
19.10.2012, 10:56 #10
turbanoff, забыли третий случай (компилируемый без инвоков)
C#
1
2
object A = new MyClass(); //Переменная A: Фактически тип = MyClass, тип переменной = object
MyClass refOb = (MyClass) A; // ok
1
temcha
28 / 28 / 5
Регистрация: 07.09.2012
Сообщений: 119
19.10.2012, 15:39  [ТС] #11
C#
1
2
object invokeResult = m.Invoke(reflectOb, args); //Переменная invokeResult: Фактический тип = MyClass, тип переменной = object
refOb=(MyClass)invokeResult;//Переменная refOb: Фактический тип = MyClass, тип переменной = MyClass. Все хорошо, ошибки не происходит
С этим немного разобрался, спасибо. Но если, как Вы говорите, метод Invoke() возвращает фактически MyClass, то почему тогда не будет работать обычное присваивание:
C#
1
MyClass refOb=m.Invoke(reflectOb, args);
0
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
19.10.2012, 15:42 #12
temcha,
C#
1
 object invokeResult
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
19.10.2012, 15:46 #13
Цитата Сообщение от temcha Посмотреть сообщение
то почему тогда не будет работать обычное присваивание
Это сделано для читабельности кода.
Когда другой программист будет читать ваш код, он сразу видит, что тут именно происходит приведение типов, и что возможно типы могут не совпасть.
0
Psilon
Master of Orion
Эксперт .NET
5981 / 4834 / 901
Регистрация: 10.07.2011
Сообщений: 14,439
Записей в блоге: 5
Завершенные тесты: 4
19.10.2012, 15:47 #14
turbanoff, оно не будет работать без явного приведения, потому что invokeResult имеет тип object
0
turbanoff
Эксперт Java
4004 / 3739 / 738
Регистрация: 18.05.2010
Сообщений: 9,322
Записей в блоге: 11
Завершенные тесты: 1
19.10.2012, 16:32 #15
Psilon, насколько я понял, имелось ввиду почему именно компилятор требует написания этого приведения, хотя он бы мог и не требовать.
Ведь выражение "не будет работать" имеет смысл только в этом случае, так как приложение даже не будет существовать если компилятор выдаст ошибку.
0
temcha
28 / 28 / 5
Регистрация: 07.09.2012
Сообщений: 119
19.10.2012, 22:58  [ТС] #16
ой, спасибо вам) буду разбираться...

Добавлено через 5 часов 51 минуту
Не хотел новую тему создавать, вопрос немного другого рода, но все еще сражаюсь с рефлексией:
Есть строчка кода:
C#
1
Assembly asm = Assembly.LoadFrom("MyClasses.exe");
Где должен находится файл MyClass.exe что бы я его мог загрузить в новый проект, или как мне указать к нему путь?
0
19.10.2012, 22:58
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
19.10.2012, 22:58
Привет! Вот еще темы с решениями:

Приведение типов: что происходит в памяти
ЗДравствуйте! Возник вопрос: вот есть код на C++ class A { int a;...

Наследование классов и производные классы
Создайте базовый класс Геометрическая фигура, предусмотрите в нем общие...

Описать базовый и производные классы
Всем привет,язык си шарп для меня новый,помогите разобраться с заданием. В...

Создать абстрактный класс и производные классы
Помогите пожалуйста, очень надо... 1. Создать абстрактный класс Издание с...


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

Или воспользуйтесь поиском по форуму:
16
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru