2009-09-16 21 views
10

Jestem tutaj na ceglanym murze. Czy możliwe jest skopiowanie jednego boola do refowania drugiego. Rozważ ten kod. . .C#, Skopiuj jeden bool na inny (przez ref, not val)

bool a = false; 
bool b = a; 

b jest teraz całkowicie oddzielnym boolem o wartości false. Jeśli później zmienię a, nie będzie to miało wpływu na b. Czy możliwe jest wykonanie a = b przez ref? Jak to zrobić?

Wielkie dzięki

+2

Refactor tylko odwoływać się ?? –

+5

Czy możesz wyjaśnić scenariusz, w którym będziesz potrzebować czegoś takiego? – shahkalpesh

+0

dlaczego chcesz to zrobić? jeśli podasz więcej szczegółów, być może ktoś zrobi to, co naprawdę chcesz. – Zack

Odpowiedz

0

Bool jest typem wartości i nie można go skopiować przez odniesienie.

+0

bool jest po prostu skrótem dla System.Boolean. Są identyczne. –

+0

a C# bool jest System.Boolean. Są takie same i oba są typami wartości. – Zack

+0

Tak, a System.Boolean jest typem wartości. Zobacz: http://msdn.microsoft.com/en-us/library/system.boolean.aspx –

28

Nie. Ponieważ bool jest typem wartości, zawsze będzie kopiowany według wartości.

Najlepszym rozwiązaniem jest, aby owinąć bool w klasie - to nada jej typ referencyjny semantyki:

public class BoolWrapper 
{ 
    public bool Value { get; set; } 
    public BoolWrapper (bool value) { this.Value = value; } 
} 

BoolWrapper a = new BoolWrapper(false); 
BoolWrapper b = a; 
b.Value = true; 
// a.Value == true 
+2

Rzeczywiście. Chociaż nie mogę przestać się zastanawiać, dlaczego takie coś jest konieczne w pierwszym rzędzie ... – Noldorin

+4

Typy referencyjne gwarantują, że obiekt, do którego się odwołuje, będzie żył co najmniej tak długo jak referencja. Typy wartości, które nie oferują takiej gwarancji, są często przechowywane na stosie i znikają, gdy tylko wykonywanie pozostawia zakres deklaracji. Umożliwienie stworzenia trwałego i rozwiązłego odniesienia do typu wartości wymagałoby, aby komputer skopiował zmienną ze stosu przed jego zasięgiem, wskazując referencję na nową kopię; teoretycznie istnieje wiele sposobów, w jakie system mógłby to zrobić, ale wszystkie z nich dodałyby ogromnego narzutu za każdym razem, gdy dowolna zmienna opuszczała zakres. – supercat

2

może nie być to, co chcesz, ale jeśli scenariusz były takie, że chciałeś funkcję który wywołałeś, aby zmodyfikować swój lokalny boolean, możesz użyć ref lub out keyworkd.

bool a = false; 

F(ref a); 
// a now equals true 

... 

void F(ref bool x) 
{ 
x = true; 
} 
10

Dzięki @Reed za odpowiedź (+1)! Zachęcił mnie do bardziej ogólnego rozwiązania "generic"! :)

public class ValueWrapper<T> where T : struct 
{ 
    public T Value { get; set; } 
    public ValueWrapper(T value) { this.Value = value; } 
} 
+0

Czy istnieje jakiś powód, aby "Wartość" była właściwością, a nie polem? Można używać rzeczy takich jak "Interlocked.CompareExchange" na polach, ale nie na właściwościach. Być może nie ma znaczenia dla 'ValueWrapper ', ale z pewnością istotne dla 'ValueWrapper ". – supercat

+0

@supercat Używam tego pola w DataBinding, ponieważ musi to być właściwość –

+0

Widzę, że ograniczenia DataBinding mogą zmusić do korzystania z właściwości, chociaż publiczne pola mają wiele zalet w przypadkach, gdy właściwość nie jest wyraźnie wymagane. Być może rozsądnym podejściem byłoby odsłonięcie publicznego pola "Wartość" i własności "ValueAsProperty" zabezpieczonej w ten sposób? – supercat

-3

Wystarczy użyć flagi jako Nullable<bool> lub bool? i ustawić te w struktury, która jest przekazywana do metody rodzajowej. Powyższa klasa ValueWrapper<T> jest dokładnie tym, co robi Nullable<T>.

+3

Nullable jest nadal typem wartości, zobacz definicję: public struct Nullable gdzie T: struct – rfcdejong

0

Zgaduję, że musisz podać referencję, bool nie można owinąć klasą "BoolWrapper", ponieważ bool ma miejsce, którego nie możesz lub nie chcesz modyfikować.

Można to zrobić!

Najpierw zadeklarować co każde odniesienie bool będzie wyglądać

/// <summary> A reference to a bool.</summary> 
/// <param name="value">new value</param> 
/// <returns>Value of boolean</returns> 
public delegate bool BoolRef(bool? value = null); 

Teraz można zrobić odniesienie do myBool jak ten

bool myBool; // A given bool that you cannot wrap or change 
    private bool myBoolRef(bool? value) { 
     if (value != null) { 
      myBool = (bool)value; 
     } 
     return myBool; 
    } 

i używać go tak:

void myTestCaller() { 
     foo(myBoolRef); 
    } 
    void foo(BoolRef b) { 
     bool c = b(); // get myBool 
     b(true); // set myBool to true 
    } 

Ta sama sztuczka działa dla innych typów wartości, takich jak int

+0

Chciałbym wiedzieć, dlaczego jest to przegłosowane. Znalazłem to rozwiązanie przydatne w kilku przypadkach. – James

0

Miałem przypadek, w którym chciałem, aby jedna klasa zmieniła inną klasę bool - proszę zauważyć, że istnieją lepsze sposoby radzenia sobie z tą sytuacją, ale jest to dowód na to, że za pomocą akcji.

public class Class1 
{ 
    bool myBool { get; set; } 
    void changeBoolFunc(bool val) { myBool = val; } 
    public Class1() 
    { 
     Action<bool> changeBoolAction = changeBoolFunc; 
     myBool = true; 
     Console.WriteLine(myBool); // outputs "True" 
     Class2 c2 = new Class2(changeBoolAction); 
     Console.WriteLine(myBool); // outputs "False" 
    } 
} 
public class Class2 
{ 
    public Class2(Action<bool> boolChanger) { boolChanger(false); } 
} 
void Main() 
{ 
    Class1 c1 = new Class1(); 
} 
4

Małe rozszerzenie Andrey's odpowiedź ... to pozwala na przypisanie go do dowolnego typu chcesz w końcu bezpośrednio.Więc:

 ValueWrapper<bool> wrappedBool = new ValueWrapper<bool>(true); 

     bool unwrapped = wrappedBool; // you can assign it direclty: 

     if (wrappedBool) { // or use it how you'd use a bool directly 
      // ... 
     } 

public class ValueWrapper<T> 
{ 

    public T Value { get; set; } 

    public ValueWrapper() { } 

    public ValueWrapper(T value) { 
     this.Value = value; 
    } 

    public static implicit operator T(ValueWrapper<T> wrapper) 
    { 
     if (wrapper == null) { 
      return default(T); 
     } 
     return wrapper.Value; 
    } 

}