2017-12-11 13 views
5

System.Random 변수가 포함 된 개체를 깊이 복제하려고합니다. 내 응용 프로그램이 결정적이어야하고 그래서 임의의 개체 상태를 캡처해야합니다. 내 프로젝트는 .Net Core 2.0을 기반으로합니다.System.Random의 딥 클론

여기 직렬화를 사용하는 일부 깊은 복제 코드 (How do you do a deep copy of an object in .NET (C# specifically)?)를 사용하고 있습니다.

System.Random에 대한 문서는 혼합 :

직렬화

직렬화하지

  • https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netcore-2.0

    https://docs.microsoft.com/en-us/dotnet/api/system.random?view=netframework-4.7.1

  • 나는 다음과 같은 오류가 발생합니다.

    System.Runtime.Serialization.SerializationException은 =이 ', 문화, PublicKeyToken = 7cec85d7bea7798e 중립 System.Private.CoreLib, 버전 = 4.0.0.0 ='총회에서 메시지 = 유형 'System.Random'HRESULT입니다 0x8013150C 직렬화 가능으로 표시되어 있지 않습니다. 출처 = System.Runtime.Serialization.Formatters

    은 그것은 내가 원하는 방식으로 복제 할 수 System.Random 수 있습니까?

    설명하기 위해 작은 프로그램을 만들었습니다.

    아마도 컨테이너 개체는 필요하지 않지만이 구조는 내 응용 프로그램과 매우 유사합니다.

    R [비 직렬화]를 사용하면 오류가 제거되지만 비 직렬화 후에 임의의 객체가 다시 생성되지 않습니다. 난 임의의 개체를 다시 만들려고했지만 새로운 임의의 시퀀스를 시작하고 결정적인 요구 사항을 깰.

    +0

    내가 (예외가 그나마

    는 그런 다음 개체를 복제하는 Json.NET을 사용하는 Cloner 클래스를 작성할 수 있습니다. NET 4.6.2) –

    +3

    왜'System.Random'의 자신의 버전을 쓰지 않고 대신 사용 하시겠습니까? PRNG를 쓸 수있는 많은 옵션이 있습니다. 기본 [C# 소스 코드] (https://referencesource.microsoft.com/#mscorlib/system/random.cs)의 관련 부분을 직접 복사 할 수도 있습니다. – rossum

    +0

    이제 http://referencesource.microsoft.com/#mscorlib/system/random.cs,bb77e610694e64ca 에서 임의의 클래스를 복사했으며 작동하는 것처럼 보였습니다. 일부 Environment.GetResourceString 오류를 주석 처리해야했습니다. 번들로 제공되는 System.Random에서 왜 작동하지 않습니까? – xareth

    답변

    0

    JSON.NET을 사용하면됩니다.

    프로젝트 | NuGet 패키지를 관리하여 프로젝트에 "Newtonsoft.Json"(최신 안정 버전 10.0.3)을 추가하십시오.

    public static class Cloner 
    { 
        public static T Clone<T>(T source) 
        { 
         if (ReferenceEquals(source, null)) 
          return default(T); 
    
         var settings = new JsonSerializerSettings { ContractResolver = new ContractResolver() }; 
    
         return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, settings), settings); 
        } 
    
        class ContractResolver : DefaultContractResolver 
        { 
         protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization) 
         { 
          var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 
           .Select(p => base.CreateProperty(p, memberSerialization)) 
           .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance) 
            .Select(f => base.CreateProperty(f, memberSerialization))) 
           .ToList(); 
          props.ForEach(p => { p.Writable = true; p.Readable = true; }); 
          return props; 
         } 
        } 
    } 
    

    는 그런 다음과 같이 몇 가지 코드를 작성할 수 있습니다 :

    var inner = new ObjectType {R = new Random(12345)}; 
    var outer = new Container {AnObject = inner}; 
    
    var clone = Cloner.Clone(outer); 
    
    Console.WriteLine(clone.AnObject.R.Next()); // Prints 143337951 
    Console.WriteLine(outer.AnObject.R.Next()); // Also prints 143337951 
    
    +0

    위의 테스트 프로그램에서 작동했습니다. 보너스로, 이미 내 응용 프로그램에서 JSON.NET을 사용하고 있습니다. 불행히도, 나는 거기에 또 다른 문제로 직행했다. 하지만 지금은 직렬화 된 Random 클래스가 있습니다. – xareth

    0

    & 사용자 지정 serializer를 작성하고 리플렉션을 사용하여 임의의 클래스를 deserialize 할 수 있습니다. Please Check.

    다음은 코드 샘플입니다. 물론 리팩토링이 필요합니다. 방금 작동하는지 보여주기 위해 여기에 추가했습니다.

    class Program 
    { 
        static void Main(string[] args) 
        { 
         Container C = new Container(); 
    
         Console.WriteLine(C.AnObject.R.Next()); 
    
         Container CopyC = DeepClone(C); 
    
         Console.WriteLine(C.AnObject.R.Next()); 
         Console.WriteLine(CopyC.AnObject.R.Next()); 
        } 
    
        public static T DeepClone<T>(T obj) 
        { 
         using (var ms = new MemoryStream()) 
         { 
          var formatter = new BinaryFormatter(); 
          formatter.Serialize(ms, obj); //<-- error here 
          ms.Position = 0; 
    
          return (T)formatter.Deserialize(ms); 
         } 
        } 
    } 
    
    [Serializable] 
    public class Container 
    { 
        public ObjectType AnObject; 
        public Container() 
        { 
         AnObject = new ObjectType 
         { 
          R = new Random() 
         }; 
        } 
    } 
    
    [Serializable] 
    public class ObjectType : ISerializable 
    { 
    
        internal Random R; 
    
        public ObjectType() { } 
        protected ObjectType(SerializationInfo info, StreamingContext context) 
        { 
         R = new Random(); 
         var binaryFormatter = new BinaryFormatter(); 
         using (var temp = new MemoryStream(Encoding.BigEndianUnicode.GetBytes(info.GetString("_seedArr")))) 
         { 
          var arr = (int[])binaryFormatter.Deserialize(temp); 
          R.GetType().GetField("_seedArray", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(R, arr);    
         } 
    
         R.GetType().GetField("_inext", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(R, info.GetInt32("_inext")); 
         R.GetType().GetField("_inextp", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(R, info.GetInt32("_inextp")); 
        }  
    
        public virtual void GetObjectData(SerializationInfo info, StreamingContext context) 
        { 
         var binaryFormatter = new BinaryFormatter(); 
    
         var arr = R.GetType().GetField("_seedArray", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); 
    
         using (var temp = new MemoryStream()) 
         { 
          binaryFormatter.Serialize(temp, arr.GetValue(R)); 
    
          info.AddValue("_seedArr", Encoding.BigEndianUnicode.GetString(temp.ToArray())); 
         } 
    
         info.AddValue("_inext", R.GetType().GetField("_inext", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(R)); 
         info.AddValue("_inextp", R.GetType().GetField("_inextp", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).GetValue(R)); 
        } 
    
    } 
    
    +0

    또한,'_seedArray'뿐만 아니라 Random의 다른 필드를 직렬화해야한다는 것에주의하십시오. – Evk

    +0

    @Evk, 네 말이 맞아, 어떻게 작동하는지 보여주고 싶었을 뿐이야. –

    +0

    이 코드는 누군가가이 코드를 복사하여 복사 할 수 있기 때문에 위험 할 수 있습니다. – Evk