[C#] null-waardes doorgeven bij ref-parameters?

Pagina: 1
Acties:
  • 160 views sinds 30-01-2008
  • Reageer

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ik wil wat DirectShow-dingen doen vanuit .NET, en aangezien dat zo ongeveer het enige deel van DirectX is wat nog niet fatsoenlijk is geport, heb ik mijn toevlucht gezocht naar een 3rd party 'library' (voor zover je daarvan kan spreken): DirectShow.NET.
In het kort komt het erop neer dat alle DirectShow COM-interfaces herschreven zijn in C#, en dat je ze met interop moet benaderen.

Een van de functies van zo'n interface ziet er in C++ bijv. zo uit:

C++:
1
2
3
4
5
6
7
HRESULT RenderStream(
  const GUID *pCategory,
  const GUID *pType,
  IUnknown *pSource,
  IBaseFilter *pIntermediate,
  IBaseFilter *pSink
);


In C# wordt dezelfde functie (volgens die library dan) zo:
C#:
1
2
3
4
5
6
7
[PreserveSig]
int RenderStream(
  [In] ref Guid pCategory,
  [In] ref Guid pType,
  [In, MarshalAs(UnmanagedType.IUnknown)] object pSource,
  [In] IBaseFilter pfCompressor,
  [In] IBaseFilter pfRenderer);


Nu is het probleem dat de eerste 2 parameters null mogen zijn. Maar: hoe krijg ik dit vanuit c# voor elkaar? Ik mag niet schrijven RenderStream(null, null, ...), omdat 'null' geen reference is, en RenderStream(ref null, ref null, ...) mag ook niet...

Is er een constructie waarmee ik wel null-pointers door kan geven, of moet ik de signature van de methode aanpassen?

  • gorgi_19
  • Registratie: Mei 2002
  • Laatst online: 27-04 18:17

gorgi_19

Kruimeltjes zijn weer op :9

Het is een reference value, dus moet je dan niet iets doen als:
Visual Basic .NET:
1
2
3
Dim a as Object = Nothing

Me.FunctieMetReferenceValueAlsParameter(a)

:)

Digitaal onderwijsmateriaal, leermateriaal voor hbo


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 19:09

pjvandesande

GC.Collect(head);

Zoals [user=gogri_19] gaat het om een refence. Bij een reference word een object verwacht, het object word als reference meegegeven aan de functie. Omdat het een object moet zijn kun je geen null zo doorgeven, maar zul je eerst een null-object moeten maken.

C#:
1
2
3
Object nullObj = null;

Function(ref nullObj);

  • whoami
  • Registratie: December 2000
  • Laatst online: 23:54
Kan je misschien ook niet met
code:
1
System.Reflection.Missing.Value

werken.

https://fgheysels.github.io/


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

questa:
Zoals [user=gogri_19] gaat het om een refence. Bij een reference word een object verwacht, het object word als reference meegegeven aan de functie. Omdat het een object moet zijn kun je geen null zo doorgeven, maar zul je eerst een null-object moeten maken.

C#:
1
2
3
Object nullObj = null;

Function(ref nullObj);
Wat een achterlijke constructie. Hebben ze daar niks beters op kunnen bedenken :?

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 19:09

pjvandesande

GC.Collect(head);

whoami schreef op maandag 29 augustus 2005 @ 08:55:
Kan je misschien ook niet met
code:
1
System.Reflection.Missing.Value

werken.
Kun je ook niet zo als een ref meegeven, zul je hetvolgende moeten doen:
C#:
1
2
object missingValueObj = Type.Missing;
Function( ref missingValueObj );

  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
questa schreef op maandag 29 augustus 2005 @ 08:44:
Zoals [user=gogri_19] gaat het om een refence. Bij een reference word een object verwacht, het object word als reference meegegeven aan de functie. Omdat het een object moet zijn kun je geen null zo doorgeven, maar zul je eerst een null-object moeten maken.

C#:
1
2
3
Object nullObj = null;

Function(ref nullObj);
Ah, kijk. :) En ik neem aan dat Missing.Value hetzelfde doet.

Maar even voor de zekerheid, als je bovenstaande code in c++ zou vertalen, dan zou er staan:
C++:
1
2
3
4
5
6
Object *pNullObj = null;
Function(pNullObj);      //void Function(Object *pObj);

//Maar niet
Object *pNullObj = null;
Function(&pNullObj);     //void Function(Object **ppObj);

Klopt dat?

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

questa schreef op maandag 29 augustus 2005 @ 08:44:
Zoals [user=gogri_19] gaat het om een refence. Bij een reference word een object verwacht, het object word als reference meegegeven aan de functie. Omdat het een object moet zijn kun je geen null zo doorgeven, maar zul je eerst een null-object moeten maken.
Nee, de functie verwacht een variabele, geen object. Het punt is dat je de referentie van de variabele zelf meegeeft. Een null is een constante, geen variabele, en kun je dus ook niet meegeven als reference. Een variabele met de waarde null natuurlijk wel.
drm schreef op maandag 29 augustus 2005 @ 09:00:
Wat een achterlijke constructie. Hebben ze daar niks beters op kunnen bedenken :?
Zie boven, als iets een reference naar een int verwacht, hoe kun je dan een constante int meegeven als parameter? Ik denk dat je wat in de war bent door questa's uitleg :).

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

.oisyn:
Zie boven, als iets een reference naar een int verwacht, hoe kun je dan een constante int meegeven als parameter? Ik denk dat je wat in de war bent door questa's uitleg :).
Mja, ok, je kunt in het algemeen (natuurlijk) geen waardes 'by reference' meegeven:
C#:
1
2
3
4
5
public void SomeFunc ( ref int i ) {
   i = 1;
}
/* ... */
SomeFunc ( 0 ); // error

Da's logisch, we kunnen niet 1 "schrijven" in de constante int 0

Maar het probleem zit 'm dan vooral in het feit dat pointers in C++ vertaald worden naar referenties in C#. Null-pointers zijn opzich gewoon pointers naar een (constant) null-adres:
C++:
1
2
3
SomeClass * somePtr = NULL;
// oftewel:
SomeClass *somePtr = (void *) 0;
Aangezien die NULL een constante pointer is, kun je die ook gewoon meegeven als parameter:
C++:
1
2
3
4
5
6
7
8
9
10
void SomeClass::doSomething ( SomeClass *ptr );
/* ... */
someInstance.doSomething ( NULL );

// which means (1)
someInstance.doSomething ( (SomeClass *) 0 ); // impliciete cast

// and is the same as (2)
SomeClass *ptr = NULL;
someInstance.doSomething ( ptr );

Dat eerste kan in C# dus niet, dat tweede wel. Waarom is er voor het eerste geen oplossing? Omdat C++ pointers feitelijk zich vertalen in C# references, terwijl het toch verschillende concepten zijn.

Of snap ik het nou niet? :P

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Klopt :P
Je moet het niet zien als C++ pointers, maar als C++ references (heej, wat toevallig ;))

C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
void funcA(int & intRef);
void funcB(Object *& objPtrRef);

int main()
{
    int i = 4;
    funcA(i);   // ok
    funcA(4);  // error

    Object * o = NULL;
    funcB(o);  // ok
    funcB(NULL); // error
}


Die Object *& komt wellicht wat raar over, maar als je het zo ziet is het wat duidelijker:
C++:
1
2
typedef Object* ObjectPtr;
void funcB(ObjectPtr & objPtrRef);


De Object* is dus het type van je variabele, daar wil je een reference naar. Een null is geen variabele maar een constante, die kun je dus ook niet meegeven.


Overigens kent C++ dan wel weer het concept const, en voor een const reference heb je uiteraard alleen read-access. In zo'n geval is het dus niet nodig dat er een variabele bestaat waarin het resultaat gezet wordt, als er maar onder water een tijdelijke variabele wordt gemaakt waar de waarde in wordt gestopt. Dit kan in C++ dus wel:

C++:
1
2
3
4
5
6
void funcC(const int & constIntRef);

int main()
{
    funcC(3);  // hier wordt een temporary const int aangemaakt waarnaar gerefeerd wordt
}

[ Voor 27% gewijzigd door .oisyn op 29-08-2005 12:41 ]

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • drm
  • Registratie: Februari 2001
  • Laatst online: 09-06-2025

drm

f0pc0dert

.oisyn:
Klopt :P
Je moet het niet zien als C++ pointers, maar als C++ references (heej, wat toevallig ;))
[snip]
De Object* is dus het type van je variabele, daar wil je een reference naar. Een null is geen variabele maar een constante, die kun je dus ook niet meegeven.
Ja, natuurlijk, dat zat ik me net ook te bedenken inderdaad :z. De verwarring zit 'm in 't feit dat je in principe in C# natuurlijk geen by-value parameters hebt, d'r valt daar een beetje een gat tussen C# en C++, ajbwib. Maar ik zie na een beetje zoeken dat dat in .net dus opgevuld door marshalling, wat soms kennelijk ook impliciet gebeurt.

Music is the pleasure the human mind experiences from counting without being aware that it is counting
~ Gottfried Leibniz


  • MrBucket
  • Registratie: Juli 2003
  • Laatst online: 29-10-2022
Ik zit nu alleen wel met een ander probleem: deze truc
C#:
1
2
System.Guid nullGuid = null;
RenderStream(ref nullGuid, ref nullGuid, ...);

werkt niet, omdat Guids value-types zijn, geen reference types. M.a.w. de eerste regel geeft een foutmelding.

Weet iemand een soortgelijke truc om ook bij reference value-types 'null'-waardes mee te geven, of moet ik toch de method-signature aanpassen?

  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 19:09

pjvandesande

GC.Collect(head);

MrBucket schreef op maandag 29 augustus 2005 @ 14:42:
Ik zit nu alleen wel met een ander probleem: deze truc
C#:
1
2
System.Guid nullGuid = null;
RenderStream(ref nullGuid, ref nullGuid, ...);

werkt niet, omdat Guids value-types zijn, geen reference types. M.a.w. de eerste regel geeft een foutmelding.

Weet iemand een soortgelijke truc om ook bij reference value-types 'null'-waardes mee te geven, of moet ik toch de method-signature aanpassen?
Dan zou je Type.Missing moeten gebruiken of gewoon null op deze manier doorgeven:

C#:
1
2
object nullGuid = null;
RenderStream(ref nullGuid, ref nullGuid, ...);

  • .oisyn
  • Registratie: September 2000
  • Laatst online: 21:33

.oisyn

Moderator Devschuur®

Demotivational Speaker

Kan niet, de functie verwacht een Guid, geen object.

Give a man a game and he'll have fun for a day. Teach a man to make games and he'll never have fun again.


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 19:09

pjvandesande

GC.Collect(head);

.oisyn schreef op maandag 29 augustus 2005 @ 14:52:
Kan niet, de functie verwacht een Guid, geen object.
Oja... ik ben gewent dat al die dll's objects verwachten.

* pjvandesande moet is ophouden met eerst posten en dan denken |:(
Pagina: 1