none
Проблема с генериком, подскажите как быть RRS feed

  • Вопрос

  • Мне очень нужно что бы такой код компилировался:

    namespace ConsoleApplication1
    {
        class Program
        {
            static void Main(string[] args)
            {
            }
        }
    
        public unsafe class Tree<T> where T : struct 
        {
            void Test(long* ptr)
            {
                var ppc = (T*)ptr;
            }
        }
    }
    Я честно говоря не могу понять почему он не компилируется.


    26 сентября 2012 г. 20:37

Ответы

Все ответы

  • Взято отсюда:

    var ppc = (T)Marshal.PtrToStructure(new IntPtr(ptr), typeof(T));

    • Предложено в качестве ответа Abolmasov Dmitry 27 сентября 2012 г. 8:51
    • Помечено в качестве ответа Max Charp 27 сентября 2012 г. 11:25
    27 сентября 2012 г. 4:29
    Модератор
  • Там же рассказывается какие типы можно так использовать.

    Не забудьте отметить ответ, если он решит вашу проблему. Спасибо.


    Для связи [mail]

    27 сентября 2012 г. 8:52
  • Там это где? ))))
    27 сентября 2012 г. 11:26
  • По ссылке что привел ulcer в параграфе Solution Attempt 4: Unsafe Generic Approach

    Для связи [mail]

    27 сентября 2012 г. 11:32
  • К сожалению там не говорится почему нельзя использовать указатели типа Some * s; ... где:

    struct Some

    {

    public int val0;

    public int val1;

    }

    Ведь эта структура является ValueType в полном смысле.

    27 сентября 2012 г. 17:49
  • Вот что написано в спецификации:

    Неуправляемый_тип — это любой тип, не являющийся ссылочным_типом или сформированным_типом и не содержащий поля ссылочного_типа или сформированного типа на любом уровне вложенности. Иначе говоря, неуправляемым_типом является один из следующих типов:

    • sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double, decimal и bool;
    • любой перечисляемый_тип;
    • любой тип_указателя;

    любой определенный пользователем тип_структуры, который не является сформированным типом и содержащий поля только неуправляемых_типов.

    Тип_указателя не может использоваться в качестве аргумента типа (§4.4), а вывод типа (§7.5.2) не работает при вызове универсальных методов, в процессе которого в качестве аргумента типа будет выведен тип указателя.

    27 сентября 2012 г. 17:59
    Модератор
  • Я не уловил что из вашего ответа следует. Структура которую я привел является неуправляемым или управляемым типом?
    27 сентября 2012 г. 18:22
  • Так если бы вы приводили к этой структуре, то ошибки и не было бы, т.к. тип известен и Visual Studio его может проверить на соответствие стандарту. Проверьте код:

            static void Main(string[] args)
            {
               
            }
            public unsafe class Tree
            {
                void Test(long* ptr)
                {
                    //var ppc = (T)Marshal.PtrToStructure(new IntPtr(ptr), typeof(T));
                    var ppc = (Some*)ptr;
                }
            }
            struct Some
            {
                public int val0;
                public int val1;
            }

    Но у вас в вопросе используется генерик и тип T может быть любой структурой, а не только содержащей простые поля, компилятор не знает что именно вы передадите и поэтому запрещает использование кода, как в изначальном вопросе.

    Для связи [mail]

    28 сентября 2012 г. 7:05
  • А почему бы компилятору не проверять это во время использования генериков? И выдавать ошибку уже по месту, там где используются не простые поля выдавать ошибку. Как в этом примере. p0 объявляется а p1 нет. 

            static void Main(string[] args)
            {
                long ppc = 123;
                long* ptr = &ppc;
    
                var p0 = (TestStruct*)ptr;
                var p1 = (ManagedStruct*)ptr; // Ошибка
            }
        }
    
        struct ManagedStruct
        {
            public int Val0;
            public int Val1;
            public FileInfo File;
        }
    
        struct TestStruct
        {
            public int Val0;
            public int Val1;
        }

    И здесь поведение должно быть аналогично:

            static void Main(string[] args)
            {
                long ppc = 123;
                long* ptr = &ppc;
    
                var p0 = SomeCast<TestStruct>(ptr);
                var p1 = SomeCast<ManagedStruct>(ptr); // Выдавать ошибку только здесь
            }
    
            static T* SomeCast<T>(long* arg) where T: struct
            {
                return (T*)arg;
            }
    
        struct ManagedStruct
        {
            public int Val0;
            public int Val1;
            public FileInfo File;
        }
    
        struct TestStruct
        {
            public int Val0;
            public int Val1;
        }

    По крайней мере это выглядит интуитивно понятно и логично. А полный запрет T* это не понятно и не логично.






    • Изменено Max Charp 28 сентября 2012 г. 8:36
    28 сентября 2012 г. 8:19
  • Нет, это не возможно сделать, т.к. представьте что вы выделили этот код в библиотеку и функцию будет вызывать другой код о котором на момент компиляции вообще ничего не известно. Плюс к этому само устройство дженериков другое, они не компилируются в перегрузки функций для тех типов, что вы вызываете, а разрешаются в рантайме (если я ничего не путаю).

    Для связи [mail]

    28 сентября 2012 г. 9:08
  • Ведь тот другой код тоже будет компилироваться, и в момент его компиляции можно производить проверку корректность использования генерика.

    • Изменено Max Charp 28 сентября 2012 г. 18:54
    28 сентября 2012 г. 18:53