2010-07-23 2 views
2

은의 당신이 스텁로 시작한다고 가정 해 봅시다 :어떻게

[<Serializable>] 
type Bounderizer = 
val mutable _boundRect : Rectangle 

new (boundRect : Rectangle) = { _boundRect = boundRect ; } 
new() = { _boundRect = Rectangle(0, 0, 1, 1); } 
new (info:SerializationInfo, context:StreamingContext) = 
    { // to do 
    } 

interface ISerializable with 
    member this.GetObjectData(info, context) = 
     if info = null then raise(ArgumentNullException("info")) 
     info.AddValue("BoundRect", this._boundRect) 

    // TODO - add BoundRect property 

문제는 스펙이 "클래스가 봉인되지 않은 경우 일반적으로,이 생성자는 보호되어야한다."라고 말한다이다 F #에는 보호 된 키워드가 없습니다. 어떻게해야합니까?

제약 (때문에 요구 사항에 완벽하게 API 레벨에서의 C# 클래스를 기존의 일치) :

  1. 생성자는

EDIT를 보호해야를 ISerializable을 구현해야합니다 - 흥미 추가 정보 를 F # 스펙에 따르면 보호 된 함수를 재정의하면 결과 함수가 보호됩니다. 이것은 잘못되었습니다. 접근성을 지정하지 않으면 결과 무시가 무엇이든지 공개됩니다 (계약 위반).

답변

2

. 이것을 할 수 있으며 두 가지 방법이 있습니다.

첫 번째는 ILDASM을 통해 출력 어셈블리를 실행하고, 원하는 메서드 선언에 regex하고, 원하는 메서드에서 'public'을 'family'로 변경 한 다음 ILASM으로 다시 반환합니다. Ewwwww.

내가 조사하고있어 두 번째는, 다음 ProtectedAttribute을 한 후 속성을 제거보다 모든 방법에 접근성을 변경 CCI와 필터를 쓰기

[<Protected>] 

와 방법에 태그를하는 것입니다. 이것은 파일에 대해 정규식을 실행하는 것보다 덜보기 흉한 것으로 보이지만 작업중인 보안 설정은 CCI 프로젝트 소스를 심각하게 싫어하므로 성공적으로 가져 오거나 압축을 풀거나 빌드 할 수 없습니다.

EDIT - 여기 내 해결책이 있습니다. CCI를 시도했지만 작업 준비가되지 않았습니다.나는 Cecil를 사용하여 종료하고 다음 코드로 결국 : F 번호에

먼저 속성

개방 시스템

[<AttributeUsage(AttributeTargets.Method ||| AttributeTargets.Constructor, AllowMultiple=false, Inherited=true)>] 
type MyProtectedAttribute() = 
    inherit System.Attribute() 

다음 Cecil의 클라이언트입니다 다음 응용 프로그램 :

using System; 
using System.Collections.Generic; 
using System.Data.Linq; 
using System.Text; 
using Mono.Cecil; 
using Mono.Collections.Generic; 
using System.IO; 

namespace AddProtectedAttribute 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      if (args.Length != 1 || args.Length != 3) 
      { 
       Console.Error.WriteLine("Usage: AddProtectedAttribute assembly-file.dll /output output-file.dll"); 
       return; 
      } 

      string outputFile = args.Length == 3 ? args[2] : null; 

      ModuleDefinition module = null; 
      try 
      { 
       module = ModuleDefinition.ReadModule(args[0]); 
      } 
      catch (Exception err) 
      { 
       Console.Error.WriteLine("Unable to read assembly " + args[0] + ": " + err.Message); 
       return; 
      } 

      foreach (TypeDefinition type in module.Types) 
      { 
       foreach (MethodDefinition method in type.Methods) 
       { 
        int attrIndex = attributeIndex(method.CustomAttributes); 
        if (attrIndex < 0) 
         continue; 
        method.CustomAttributes.RemoveAt(attrIndex); 
        if (method.IsPublic) 
         method.IsPublic = false; 
        if (method.IsPrivate) 
         method.IsPrivate = false; 
        method.IsFamily = true; 
       } 
      } 

      if (outputFile != null) 
      { 
       try 
       { 
        module.Write(outputFile); 
       } 
       catch (Exception err) 
       { 
        Console.Error.WriteLine("Unable to write to output file " + outputFile + ": " + err.Message); 
        return; 
       } 
      } 
      else 
      { 
       outputFile = Path.GetTempFileName(); 
       try 
       { 
        module.Write(outputFile); 
       } 
       catch (Exception err) 
       { 
        Console.Error.WriteLine("Unable to write to output file " + outputFile + ": " + err.Message); 
        if (File.Exists(outputFile)) 
         File.Delete(outputFile); 
        return; 
       } 
       try 
       { 
        File.Copy(outputFile, args[0]); 
       } 
       catch (Exception err) 
       { 
        Console.Error.WriteLine("Unable to copy over original file " + outputFile + ": " + err.Message); 
        return; 
       } 
       finally 
       { 
        if (File.Exists(outputFile)) 
         File.Delete(outputFile); 
       } 
      } 
     } 

     static int attributeIndex(Collection<CustomAttribute> coll) 
     { 
      if (coll == null) 
       return -1; 
      for (int i = 0; i < coll.Count; i++) 
      { 
       CustomAttribute attr = coll[i]; 
       if (attr.AttributeType.Name == "MyProtectedAttribute") 
        return i; 
      } 
      return -1; 
     } 
    } 
} 

마지막으로 MyProtectedAttribute를 사용하여 보호하려는 메서드를 꾸미고 C# 응용 프로그램을 빌드 후 작업으로 실행합니다. 어서.

1

불행히도 F #에는 보호 된 구성원이 없습니다. 우리는 차후 버전에서 이것을 고려할 것입니다.

1

사실 보호 수정은 집행하지 않지만 직렬화하는 동안 recommendation

는 SerializationInfo에이 목적을 위해 제공되는 생성자를 사용하여 클래스에 전달됩니다. 객체가 deserialize 될 때 생성자에 대한 가시성 제약 조건은 무시됩니다. 따라서 클래스를 public, protected, internal 또는 private으로 표시 할 수 있습니다.

그래서이 작동합니다 : 그대로 현재 언어를 사용하여이 작업을 수행 할 수 없습니다

[<Serializable>] 
type Bounderizer = 
    val mutable _boundRect : Rectangle 

    new (boundRect : Rectangle) = { _boundRect = boundRect ; } 
    new() = { _boundRect = Rectangle(0, 0, 1, 1); } 
    private new (info:SerializationInfo, context:StreamingContext) = 
     Bounderizer(info.GetValue("BoundRect", typeof<Rectangle>) :?> Rectangle) 
     then 
      printfn "serialization ctor" 

    interface ISerializable with 
     member this.GetObjectData(info, context) = 
      if info = null then raise(ArgumentNullException("info")) 
      info.AddValue("BoundRect", this._boundRect) 

    override this.ToString() = this._boundRect.ToString() 

let x = Bounderizer(Rectangle(10, 10, 50, 50)) 
let ms = new MemoryStream() 
let f = new BinaryFormatter() 
f.Serialize(ms, x) 
ms.Position <- 0L 
let y = f.Deserialize(ms) :?> Bounderizer 
printfn "%O" y 
(* 
serialization ctor 
{X=10,Y=10,Width=50,Height=50} 
*) 
+1

물론 기존 API를 정확히 일치시키는 제약이 있습니다. – plinth