2009-10-11 15 views
29

Nie jestem pewien, czy jestem całkowicie brakuje czegoś tutaj, ale nie mogę znaleźć sposobu, aby określić, czy parametr jest przekazywany przez odniesienie, czy nie, za pomocą refleksji.Ref parametry i odbicie

ArgumentInfo ma właściwość "IsOut", ale nie ma wartości "IsRef". Jak chciałbym uzyskać wszystkie parametry odniesienia w danym MethodInfo?

+0

Uważaj, @Patrik Hägne. IsOut nie oznacza nawet, że parametr jest przekazywany przez odniesienie. Oznacza to, że nie oznacza to, że parametr jest parametrem "out". Jak niedawno odkryłem, ku mojemu rozczarowaniu. –

+0

@BlairConrad: czy możesz rozwinąć powyższy komentarz? W jakich sytuacjach IsOut nie oznacza, że ​​parametr jest parametrem "out"? – RobSiklos

+0

@RobSiklos, jasne. Obrzydliwa historia jest opowiedziana w [komentarz w FakeItEasy numer 508] (https://github.com/FakeItEasy/FakeItEasy/issues/508#issuecomment-122147155). Niektóre parametry są ozdobione '[Out]'. Na przykład, bufor w 'Stream.Read (byte [], int, int)'. –

Odpowiedz

35
ParameterInfo[] parameters = myMethodInfo.GetParameters(); 
foreach(ParameterInfo parameter in parameters) 
{ 
    bool isRef = parameterInfo.ParameterType.IsByRef; 
} 
+2

IsByRef określa tylko, czy Typ jest typem referencyjnym, czy typem Typu, o ile wiem, nie mówi, czy Typ jest przekazywany przez odniesienie –

+5

Jorge: O ile rozumiem, "IsByRef" określa jeśli typ jest przekazywany przez odniesienie, a nie, jeśli jest to typ odniesienia. Na przykład typ System.Object ma wartość "IsByRef" false, jednak specjalny typ System.Object & ma wartość "IsByRef true." –

+9

Jorge: To, o czym mówisz, to 'IsValueType', a nie' IsByRef'. –

7

Musisz sprawdzić typ swojego parametru dalej. Na przykład, jeśli masz

void Foo(ref int bar) 

następnie nazwa parametru nie byłoby int lub Int32 (jak można się spodziewać), ale zamiast Int32&. Dla każdego typu istnieje odpowiedni by-ref-type, w którym oryginalny typ ma przyrostek "&". Możesz to sprawdzić poprzez właściwość IsByRef klasy Type.

1

ParametrInfo.ParameterType.IsByRef zwraca wartość true, jeśli deklaracja parametru jest ze słowem kluczowym ByRef i zwraca wartość false, jeśli deklaracja jest ze słowem kluczowym ByVal (niezależnie od tego, czy typ parametru jest wartością dodatkową (np. struktura) lub przez odniesienie (np. klasa)).

Aby zilustrować, rozważmy następującą strukturę i klasę (używam kodu VB):

' Empty structure and class, just for illustration. 
Public Structure MyStruct 
End Structure 

Public Class MyClass1 
End Class 

I załóżmy, że masz następującą metodę, która pobiera ByVal i ByRef argumenty dotyczące struktury i klasy zdefiniowanej powyżej (pamiętać, że wychodząc z VB 2012, można pominąć słowa kluczowego ByVal gdyż jest to ustawienie domyślne):

Public Sub P(s1 As MyStruct, ByRef s2 As MyStruct, c1 As MyClass1, ByRef c2 As MyClass1) 
End Sub 

teraz następujący kod testuje metodę ParameterInfo.ParameterType.IsByRef:

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
     ' Reflect on method P: 
    Dim mi As MethodInfo = Me.GetType.GetMethod("P") 
    ' Iterate all parameters, and call its ParameterType.IsByRef method: 
    For Each pi As ParameterInfo In mi.GetParameters 
     If **pi.ParameterType.IsByRef** _ 
     Then Console.WriteLine(pi.Name & " is ByRef") _ 
     Else Console.WriteLine(pi.Name & " is ByVal") 
    Next 
End Sub 

otrzymasz następujący komunikat:

s1 is ByVal 
s2 is ByRef 
c1 is ByVal 
c2 is ByRef 

Jak widać, ParameterInfo.ParameterType.IsByRef zwraca true argumentów s2 i C2, ponieważ są one określone za pomocą słowa kluczowego ByRef, choć jeden z jest to struktura (typ wartości), a druga to klasa (typ odniesienia); i zwraca wartość false dla argumentów zdefiniowanych za pomocą słowa kluczowego ByVal.

Należy jednak zauważyć, że słowo kluczowe ByVal nie oznacza, że ​​wszystkie argumenty zostaną przekazane jako kopia. Nawet jeśli używane jest to słowo kluczowe (ByVal), jeśli typ jest odsyłaczem (np. Klasa), argument zostanie przekazany jako odniesienie, tak jakby użyto słowa kluczowego ByRef. Oznacza to, że c1 i c2 powyższej metody P OBIEĆ będą przekazywane przez odniesienie, co oznacza, że ​​jeśli P zmieni pole lub właściwość na c1 lub c2, zmiany zostaną odzwierciedlone dla osoby wywołującej. (ByVal i ByRef aby różnica głównie gdy typ to wartość, na przykład w postaci struktury).

5

ParameterType.IsByRef powróci true zarówno refiout parametrów.

Jeśli masz obiekt ParameterInfo (np.z MethodInfo.GetParameters()), a następnie:

  • param jest out jeśli parameterInfo.ParameterType.IsByRef && parameterInfo.IsOut
  • param jest ref jeśli parameterInfo.ParameterType.IsByRef && parameterInfo.IsOut == false

Jeśli nie zrobić czek IsByRef dla out parametrów Pokochasz więc niepoprawnie pobrano elementy za pomocą atrybutu [Out] z System.Runtime.InteropServices, ale które w rzeczywistości nie są parametrami C# out.

0

jeśli sędzią jest parameterInfo.IsIn == true && parameterInfo.IsOut == true wtedy nie może wymagać, jeśli parameterInfo.ParameterType.IsByRef wcale

+0

Proszę użyć wycofania do podświetl kod wbudowany i edytuj odpowiedź, aby była bardziej czytelna (nie potrafię odczytać zdania). –