2015-01-31 3 views
0

Я ищу пример C Sharp абстрактного метода с общим прототипом, что полученные методы переопределения могут получать разную структуру параметров.передать параметры методу как void * в C++

пример из C++

class IBase { 
public: 
    virtual void method(void * pParameters) = 0; 
} 

class CDerivedA : public IBase { 
public: 
    struct S_A { 
    char a; 
    short b; 
    } 
    virtual void method(void * pParameters); 
} 

void CDerivedA::method(void * pParameters) { 
    S_A * pSa = (S_A *)pParameters; 
    pSa->a 
    pSa->b 
} 

class CDerivedB : public IBase { 
public: 
    struct S_B { 
    long c; 
    float d; 
    double e; 
    } 
    virtual void method(void * pParameters); 
} 

void CDerivedB::method(void * pParameters) { 
    S_B * pSb = (S_B *)pParameters; 
    pSb->c 
    pSb->d 
    pSb->e 
} 

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

Я нашел 2 варианта реализации этого в C#: 1.

interface IBase { 
    void method(object parameters); 
} 

class CDerivedA : IBase { 
    void method(object parameters) { 
    // cast to use the parameters 
    user obj = (user)parameters; 
    ... 
    } 
} 

class CDerivedB : IBase { 
    void method(object parameters) { 
    // cast to use the parameters 
    point obj = (point)parameters; 
    ... 
    } 
} 

2.

interface IBase { 
    void method(dynamic parameters); 
} 

class CDerivedA : IBase { 
    // directly use the parameters 
    void method(dynamic parameters) { 
    ... 
    } 
} 

class CDerivedB : IBase { 
    // directly use the parameters 
    void method(dynamic parameters) { 
    ... 
    } 
} 

ведьма лучше/быстрее?

+0

Мне совершенно непонятно, что вы просите. Вы показали код на C++ (с некоторым очень сомнительным поведением) - как это связано с вопросом C#? Однако передача классов по ссылке * не * быстрее, чем передача их по значению в C#. –

+1

@ Konrad: Как вы даже передаете класс C# по значению? – James

+0

Как правило, это очень плохая идея для порта 1: 1 при переходе на другой язык. Можете ли вы показать пример C#, чтобы мы могли видеть, что вы на самом деле пытались сделать и не работали должным образом? – walther

ответ

3

Поскольку C# - управляемый язык, нет такой вещи, как void* (что никогда не было действительно хорошей идеей даже в C++). У вас есть два варианта в C#: передать «объект» или использовать генерики. Объект должен быть добавлен к соответствующему типу, который будет использоваться как что-либо, кроме черного ящика. Generics (менее мощная версия шаблонов C#) обычно - путь.

Если вам нужно передать несколько параметров, вы можете использовать C# Tuple (по аналогии с C void* массив) или объект массив params (похожий на C) переменной длины.

В отсутствие хорошего примера того, почему это было бы полезно (если это возможно), это выглядит плохой дизайн.

Я могу видеть из комментариев, что есть много путаницы на эту тему, так что позвольте мне быть абсолютно ясно: class и struct в C# и C++ является очень разные. В C++ различие заключается в построении и публичном/частном доступе к полям. В C# различие заключается в том, как они обрабатываются при передаче в качестве параметров.

В C# при объявлении класса и пропуск «класс» (экземпляра класса, на самом деле) в функцию, вы действительно пропускание ссылки к экземпляру класса в функцию. Существует никоим образом, чтобы передать экземпляр класса непосредственно в функцию, как вы можете в C++. В отличие от C++, в C# функция, которую вы вызываете, может изменять данные в экземпляре класса, и такие изменения будут видны вызывающей стороне, потому что на C++ вызывается конструктор копирования и данные экземпляра класса фактически копируются в стек, но в C#, классы ссылки типы.

Вот некоторые примеры, предполагая, что C является class и S является struct на обоих языках:

В C++:

void func (C c) 
{ 
    c.value = true; // This change will NOT be seen by the caller because the class was passed by value 
} 

void func (C* c) 
{ 
    c->value = true; // This change WILL be seen by the caller because the class was passed by reference (pointer in this case, though the distinction is only syntactic) 
    c = new C();  // This new instance will not be seen by the caller and will never be destroyed or freed 
} 

void func (C& c) 
{ 
    c.value = true; // This change WILL be seen by the caller because the class was passed by reference 
} 

void func (C** c) 
{ 
    (*c)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function 
    *c = new C();  // A new instance of C WILL be seen by the caller because the pointer to the class was passed by reference (pointer) 
} 

void func (S s) 
{ 
    s.value = true; // This change will NOT be seen by the caller because the struct was passed by value 
} 

void func (S* s) 
{ 
    s->value = true; // This change WILL be seen by the caller because the struct was passed by reference (pointer) 
    s = new S();  // This new instance will not be seen by the caller and will never be destroyed or freed 
} 

void func (S& s) 
{ 
    s.value = true; // This change WILL be seen by the caller because the struct was passed by reference 
} 

void func (S** s) 
{ 
    (*s)->value = true; // This change will only be seen by the caller if they kept another pointer (reference) to the instance, because the next statement will overwrite the pointer whose pointer was passed into this function 
    *s = new S();  // A new instance of S WILL be seen by the caller because the pointer to the struct was passed by reference (pointer) 
} 

И в C#:

void func (C c) 
{ 
    c.value = true; // This change will be seen by the caller because the class was passed by reference 
} 

void func (ref C c) 
{ 
    c.value = true; // This change will only be seen by the caller if they kept another reference to the class instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function 
    c = new C();  // A new instance of C WILL be seen by the caller because the reference to the class was passed (by reference) 
} 

void func (S s) 
{ 
    s.value = true; // This change will NOT be seen by the caller because the struct was passed by value 
} 

void func (ref S s) 
{ 
    s.value = true; // This change will only be seen by the caller if they kept another reference to the struct instance other than the one they passed by reference to this function, because the next statement will overwrite the reference whose reference was passed into this function. I think this would require boxing the original struct instance. 
    s = new S();  // A new instance of S WILL be seen by the caller because the struct was passed by reference 
} 

Перейти фактические данные (не ссылки/указатели) по значению в C#, данные должны будет объявлен как struct.Для получения дополнительной информации см. Microsoft's explanation of structs vs. classes in C#.

+3

В C# * ссылки * передаются методам * по значению *, если они явно не переданы по ссылке с ключевыми словами 'ref' или' out'. –

+0

@Престон: правильный. Я отредактировал, чтобы надеяться прояснить любое недоразумение. В C# классы - это всегда * ссылки и структуры обычно по значению (если не использовать ключевое слово 'ref' или' out', и даже тогда вы должны быть осторожны). В C++ оба значения по умолчанию (поэтому большинство функций C++ принимают указатель * на класс * в параметрах). – James

Смежные вопросы