2014-06-20 6 views
7

다양한 변수의 참조를 사전에 해당 키와 함께 저장하는 방법을 찾고 있습니다. 그럼 그 열쇠로 사전을 통해 참조에 액세스하여 변수의 인스턴스를 수정하고 싶습니다. 참조를 저장하는 데 성공했지만 <object>을 사용하려고했습니다. 사전이나 목록에는 Dictionary<string, ref int>과 같은 것도 허용되지 않습니다. 다음 코드는 컴파일되지만 값으로 변수를 업데이트하는 것처럼 보입니다. 어떤 아이디어 또는 해결 방법? 여기 사전에있는 객체에 대한 참조 저장

은 (테스트) 코드입니다 :

class Test1 
{ 
    IDictionary<string, object> MyDict = new Dictionary<string, object>(); 

    public void saveVar(string key, ref int v) //storing the ref to an int 
    { 
     MyDict.Add(key, v); 
    } 
    public void saveVar(string key, ref string s) //storing the ref to a string 
    { 
     MyDict.Add(key, s); 
    } 

    public void changeVar(string key) //changing any of them 
    { 
     if(MyDict.GetType() == typeof(int)) 
     { 
      MyDict[key] = (int)MyDict[key] * 2; 
     } 
     if(MyDict.GetType() == typeof(string)) 
     { 
      MyDict[key] = "Hello"; 
     } 
    } 
} 

그리고 이것은 내가

Test1 t1 = new Test1(); 
int myInt = 3; 
string myString = "defaultString"; 

Console.WriteLine(myInt); //returns "3" 
Console.WriteLine(myString); //returns "defaultString" 

t1.saveVar("key1", ref myInt); 
t1.saveVar("key2", ref myString); 

t1.changeVar("key1"); 
t1.changeVar("key2"); 

Console.WriteLine(myInt); //should return "6" 
Console.WriteLine(myString); //should return "Hello" 
+0

: 당신이 무엇을 할 수 있는지

그러나,이 같은 것이, 단순히 참조 형의 값 유형을 포장입니까? – Max

+0

문자열은 참조 유형이므로 참조에 대한 참조를 저장 하시겠습니까? –

+1

그럴 수 없습니다. – SLaks

답변

6

제가 생각할 수있는 최선의 해결책은 변수를 검색하고 수정할 수있는 대리인을 사전에 저장하는 것입니다.

sealed class VariableReference 
{ 
    public Func<object> Get { get; private set; } 
    public Action<object> Set { get; private set; } 
    public VariableReference(Func<object> getter, Action<object> setter) 
    { 
     Get = getter; 
     Set = setter; 
    } 
} 

사전은 종류 것 :

의이 게터와 세터 대표가 포함 된 유형 선언에 의해 시작하자

Dictionary<string, VariableReference> 

변수를 저장하려면 다음을 입력 stringfoo 말 , 사전에서 다음을 작성하십시오.

myDic.Add(key, new VariableReference(
    () => foo,      // getter 
    val => { foo = (string) val; } // setter 
)); 

var value = myDic[key].Get(); 

변화newValue에 변수의 값 하려면

myDic[key].Set(newValue); 

이 방법, 변수를 써서

, 당신은 써서 변수의 을 검색하려면 원래 변수 인 foofoo은 무엇이든 변경할 수 있습니다 (로컬 변수, 매개 변수, 객체의 필드, 정적 필드 ... 심지어 속성 인).).외에도 케빈 지적 문제에서

class Test1 
{ 
    Dictionary<string, VariableReference> MyDict = new Dictionary<string, VariableReference>(); 

    public void saveVar(string key, Func<object> getter, Action<object> setter) 
    { 
     MyDict.Add(key, new VariableReference(getter, setter)); 
    } 

    public void changeVar(string key) // changing any of them 
    { 
     if (MyDict[key].Get() is int) 
     { 
      MyDict[key].Set((int)MyDict[key].Get() * 2); 
     } 
     else if (MyDict[key].Get() is string) 
     { 
      MyDict[key].Set("Hello"); 
     } 
    } 
} 

// ... 

Test1 t1 = new Test1(); 
int myInt = 3; 
string myString = "defaultString"; 

Console.WriteLine(myInt); // prints "3" 
Console.WriteLine(myString); // prints "defaultString" 

t1.saveVar("key1",() => myInt, v => { myInt = (int) v; }); 
t1.saveVar("key2",() => myString, v => { myString = (string) v; }); 

t1.changeVar("key1"); 
t1.changeVar("key2"); 

Console.WriteLine(myInt); // actually prints "6" 
Console.WriteLine(myString); // actually prints "Hello" 
+0

감사합니다. Timwi, 해결했습니다. 그냥 예제를 컴파일하고 작동합니다. –

+1

이 기능은 다소 복잡합니다. 그리고 그것은 변수 캡처가 람다에서 어떻게 작동하는지 이해하지 못하는 사람들에게 어떻게 작동하는지에 관해서는 매우 혼란 스러울 수 있습니다. 말하자면, 올바르게 사용하지 않으면 변수 캡처 범위 지정에 문제가있을 수 있습니다 ... –

+0

@ErikFunkenbusch : 변수를 캡처해도 범위가 변경되지 않습니다. 이 솔루션의 장점은 람다 변수 캡처를 이해할 필요가 없다는 것입니다. 그것은 실제로 작동합니다 ... – Timwi

-1

ref 매개 변수의 참조를 호출하는 방법의 범위를 떠날 수 없다 클래스의 메소드를 호출하는 방법입니다 그것. 이는 참조 인 변수가 메소드 호출이 완료된 후에 범위 내에 있음을 보장 할 수 없기 때문입니다. 호출자가 사용하는 변수를 변경할 수 있도록 간접적 인 계층을 만들려면 ref 이외의 도구를 사용해야합니다.

이 작업은 상당히 쉽습니다. 당신은 간단하게 변경 가능한 멤버 클래스를 필요

public class Pointer 
{ 
    public object Value { get; set; } 
} 

이제 쓸 수 있습니다 :

class Test1 
{ 
    IDictionary<string, Pointer> MyDict = new Dictionary<string, Pointer>(); 

    public void saveVar(string key, Pointer pointer) //storing the ref to an int 
    { 
     MyDict.Add(key, pointer); 
    } 

    public void changeVar(string key) //changing any of them 
    { 
     if (MyDict[key].Value.GetType() == typeof(int)) 
     { 
      MyDict[key].Value = (int)(MyDict[key].Value) * 2; 
     } 
     if (MyDict[key].Value.GetType() == typeof(string)) 
     { 
      MyDict[key].Value = "Hello"; 
     } 
    } 
} 

이제 호출자가도에 대한 참조를 가지고 참조 형식을 돌연변이하고 있기 때문에, 그들은 관찰 할 수있다 그 가치에 대한 변화.

+0

typeof (Dict)가 typeof (int) 또는 typeof (string)과 결코 같지 않으므로 changevar 코드가 실행되지 않습니다. –

+0

@KevinCook 예, 값의 형태 – Servy

-2

, 당신이 참조 타입의 어떤 종류에 값 형식을 래핑해야합니다 모두 함께이 퍼팅

,이 클래스 Test1의 모습 것입니다.

문제는 알아 낸 것처럼 일반적인 키워드 유형이 ref 키워드와 함께 작동하지 않으며 사전에 새 값 유형을 할당하면 참조가 다른 참조로 대체되고 업데이트되지는 않습니다 그것. Ref semantics를 사전에 할당하면 ref semantics를 유지할 수 없습니다. 당신은 사전의 키를 업데이트 할

public class MyRef<T> { 
    public T Ref {get;set;} 
} 

public class Test1 
{ 
    Dictionary<string, object> MyDict = new Dictionary<string, object>(); 

    public void saveVar(string key, object v) 
    { 
     MyDict.Add(key, v); 
    } 

    public void changeVar(string key, object newValue) //changing any of them 
    { 
     var ref1 = MyDict[key] as MyRef<int>; 
     if (ref1 != null) { 
      ref1.Ref = (int)newValue; 
      return; // no sense in wasting cpu cycles 
     } 

     var ref2 = MyDict[key] as MyRef<string>; 
     if (ref2 != null) { 
      ref2.Ref = newValue.ToString(); 
     } 
    } 

    public void DoIt() 
    { 
     var v = new MyRef<int> { Ref = 1 }; 

     saveVar("First", v); 
     changeVar("First", 2); 

     Console.WriteLine(v.Ref.ToString()); // Should print 2 
     Console.WriteLine(((MyRef<int>)MyDict["First"]).Ref.ToString()); // should also print 2 
    } 
} 
+0

컴파일되지 않습니다. 당신은 당신의 사전의 가치에 대해하고있는'객체'에'Ref'를 부를 수 없습니다. – Servy

+0

Servy - 네가 맞아, 고마워, 이걸 수정 해. 컴파일하고 테스트 해. 작동 해. –

+3

downvoting 누구든지 솔루션 작동합니다. 솔루션이 잘못되었거나 작동하지 않거나 중요한 문제가있어서 다른 솔루션을 더 좋아한다고 downvote하지 마십시오. 다른 솔루션을 더 좋아한다면, 그 솔루션을 upvote하지만 그것은 개인적인 취향에만 다른 답변에 중립적입니다. –

관련 문제