2010-01-29 8 views
9

Mam klasę, która jest w większości opakowaniem dla dużej tablicy i niektórych związanych z nią porządków. Mam funkcję, która przyjmuje parametr ref. Kiedy przekazuję instancję klasy do funkcji, chcę, aby tablica została wysłana.Przekazywanie jawnego rzutowania jako parametru ref (C#)

Zastanawiam się nad wyraźnymi rzutami. Powiedzmy, że mam jakąś funkcję, która ma parametr wartości bajtu [].

public void SomeFunction(ref byte[] someBytes); 

A że mam jakąś klasę z przeładowanym wyraźnej obsady.

class SomeClass 
    { 
     byte[] someBytes; 
     public static explicit operator byte[](SomeClass someInstance) 
     { 
      return someInstance.someBytes; 
     } 
    } 

Teraz chcę wywołać funkcję z klasy jako parametr

SomeClass someInstance = new SomeClass(); 
    SomeFunction(ref (byte[]) someInstance); 

Kompilator narzeka „ref lub out argument musi być zmienną cesji”. Nie jestem pewien, czy po prostu nie masuję poprawnie kompilatora, czy naprawdę nie można tego zrobić.

Uważałem wartości zwracanej właściwości lub funkcji, ale nie można przejść przez te ref (a po edukowanie siebie widzę dlaczego ...)

wolałbym nie robić tablica pole publicznego , ale to satysfakcjonuje kompilator. Przypuszczam może po prostu utworzyć lokalną zmienną do odwoływania się tablicę, ale to dodatkowy wiersz kodu przed i po każdym wywołaniu funkcji ...

EDIT: może warto zauważyć, że został napisany przez SomeFunction strony trzeciej i nie mam dostępu, aby to zmienić. Co gorsza, nie sądzę, aby ich parametr rzeczywiście musiał być ref ...

Odpowiedz

9

Odlew nie jest zmienną możliwą do przypisania; przekazujesz wartość zwracaną przez operatora przesyłania jawnego.

Można utworzyć zmienną gospodarstwa wartość prawidłowo oddanych przed przekazaniem go jako ref:

SomeClass someInstance = new SomeClass(); 
byte[] someBytes = (byte[])someInstance; 
SomeFunction(ref someBytes); 

Należy pamiętać, że to jest teraz someBytes zmienna, która może być przeniesiony. Będziesz musiał podjąć działania, aby ponownie przydzielić someInstance.someBytes w jakiś sposób po wywołaniu SomeFunction, jeśli chcesz, aby wewnętrzna wartość someInstance została ponownie przypisana.

+0

Tak więc okazuje się, że praktyczne rozwiązanie byłoby być albo pole publicznego lub krótki metoda, której jedynym celem jest, aby zatuszować stworzenie jakiejś zmiennej lokalnej przejść. Ja nie kilka kopanie i rodzajowych może pomóc , także. – ajs410

+0

W porządku, prosty setter wystarczyłby do aktualizacji jakiejś inwentarza. Alternatywnie można utworzyć interfejs, który funkcja SomeFunction przyjmuje jako argument, a SomeInstance implementuje i implementować logikę za pośrednictwem tego interfejsu. –

1

Nie możesz tego zrobić, musisz zmaterializować wynik rzucania obiektu do zmiennej jako pierwszej.

Rozważmy następujący kod, jeśli co prosisz pozwolono:

public void SomeFunction(ref byte[] someBytes) 
{ 
    someBytes = new byte[] { 1, 2, 3 }; 
} 

SomeClass someInstance = new SomeClass(); 
SomeFunction(ref (byte[]) someInstance); 
// uh-oh, what is "someInstance" now? 

Dlaczego jest argument z napisem „ref”, co problemem jest to, że starasz się rozwiązać tutaj?

+0

Argument jest oznaczony jako prawdopodobny, ponieważ pierwotny programista zewnętrzny przenosił bibliotekę C++ do .NET. Problem, który próbuję rozwiązać, polega na tym, że tańczę dookoła ref, nie czyniąc niektórych bajtów polem publicznym lub tworząc zmienną lokalną. Wybrałem "wyraźną obsadę", ponieważ wiedziałem, że pola porządkowe zostaną utracone. Miałem nadzieję, że jakiś Inventance po prostu przekaże odniesienie do niektórych Bajtów wraz z SomeFunction. Nie różni się zbytnio od korzystania z pola publicznego, ale wymuszanie wyraźnych rzutów sprawiłoby, że byłby mniej podatny na nadużycia. – ajs410

+1

Cóż, parametry "ref" i "out" wymagają zmiennej bazowej, naprawdę nie ma na to odwrotu, więc musisz tylko zdefiniować zmienną, jak już się dowiedziałeś. Oczywiście możesz zrobić shim-metody w swojej klasie, aby zrobić to tłumaczenie dla ciebie i zamiast tego wywołaj te metody, które z kolei wykonają rzutowanie, przechowują w zmiennej i wywołują rzeczywiste metody, ale to może nie jest dobrym rozwiązaniem. –

+0

Ostateczne rozwiązanie polega na utworzeniu lokalnej kopii odwołania do bajtu [] i odnowienia tej lokalnej kopii. To technicznie narusza punkt odniesienia, ale jestem prawie pewien, że programista stron trzecich uważał, że w C# jest taki sam jak w C++ i to nie jest prawda. – ajs410

1

Zakres wartości, które mogą być użyte jako parametr ref w języku C#, jest ograniczony przez to, co pozwala na to CLR. Jest on określony w specyfikacji CLI w rozdziałach 12.4.1.5.2 i 12.1.6.1 i obejmuje

  • argument dotychczasowego sposobu
  • zmiennej lokalnej
  • Użytkownik Pole obiektu
  • Pole Statyczne
  • Array Element

Odlewane nie pasują do żadnej z te i dlatego nie mogą być używane jako wartość ref. Musisz go przypisać do wartości lokalnej, zanim przekażesz ją przez odniesienie.

+0

Dzięki za odniesienie do specyfikacji! Przez jakiś czas nie dostałem się do C#, więc w pewnym sensie było to bardziej akademickie pytanie, ponieważ w pełni zbadałem różne funkcje tego języka ... i na pewno jest ich dużo. – ajs410

0

Czy naprawdę trzeba oddać parametr ref? W moim przypadku coś takiego działa dobrze.

byte[] someInstance = (byte[])new SomeClass(); 
SomeFunction(ref someInstance);