2017-04-18 1 views
0

(INT32, 날짜 시간) (Int32, DateTime은, 무엇이든) :열기 위임 내가 구조체의 방법 <code>ToString(string, IFormatprovider)</code>에 열려있는 대리자를 만들

public delegate string MyCoverter(ref DateTime from, string format, IFormatProvider provider); 
... 
var method = typeof(DateTime).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider)}); // Works! 
var d= Delegate.CreateDelegate(typeof(MyCoverter), null, method); // Exception! 

그것은 던지는 유지 메시지 "ArgumentException 대상 메서드에 바인딩 오류가 발생했습니다."

나는이 주제에 대한 거의 모든 유래 기사를 읽었습니다, 나는 함께하고 ref없이 실험을 내가 추가 한 및 대리자를 만들 때 null를 제거했습니다. 아무것도 도움이되는 것 같지 않습니다.

단서가 있습니까?

*이

내가 같은 방법으로 내 자신의 구조체를 만들은, 위의 코드 (날짜 시간에 내 MYSTRUCT 대체) * 편집 완벽하게 잘 작동합니다.

public struct MyStruct 
{ 
    public string ToString(string format, IFormatProvider provider) 
    { 
     return null; 
    } 
} 

은 무엇는 Int32 또는 DateTime 그래서 다른한다?

* EDIT *

나는 완전한 "작업"프로그램을 추가 요청으로. 내가 언급 한 것을 잊어 버렸습니다. .NET Framework 3.5에서 작업하고 있습니다. 또한 앞서 말한대로 MyStruct에서이 모든 작업을 수행하고 있습니다. 예외적으로 인터페이스 IFormattable을 구현하면 더 이상 작동하지 않습니다.

using System; 

namespace OpenDelegates 
{ 
    public delegate string MyCoverter<T>(ref T from, string format, IFormatProvider provider) 
     where T : struct; 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var method = typeof(MyStruct).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) }); 
      var d = Delegate.CreateDelegate(typeof(MyCoverter<MyStruct>), null, method); 

      method = typeof(DateTime).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) }); 
      d = Delegate.CreateDelegate(typeof(MyCoverter<DateTime>), null, method); 
     } 
    } 

    public struct MyStruct //: IFormattable 
    { 
     public string ToString(string format, IFormatProvider provider) 
     { 
      return null; 
     } 
    } 
} 

* EDIT *

그것은 모든 .NET 프레임 워크 4.x를 완벽하게 작동하지만, 그 날에 대한 해결책이 아니다.

+1

ToString에 대한 과부하가 없습니다. ref 매개 변수와 함께. 특히 델리게이트를'ToString' 과부하로 변환 할 수 없습니다. – HimBromBeere

+1

코드를 실행했지만 오류가 발생하지 않았습니다 ... [최소, 완료 및 확인 가능한 예제] (https://stackoverflow.com/help/mcve)를 만들 수 있습니까? –

+1

@HimBromBeere : It OPEN 델리게이트입니다. 즉, 첫 번째 매개 변수는 메서드가 작업중인 인스턴스 ('this')입니다. 일부 기사에 따르면이 매개 변수는 구조체 일 때 참조해야합니다. 참조하십시오 : http://stackoverflow.com/questions/1212346/uncurrying-an-instance-method-in-net/1212396#1212396 –

답변

3

내가 특정 문제에 대한 답을 알고하지 않습니다하지만 어쩌면 당신이 당신의 자신의 대리자를 구축 할 수는 :

public static Func<object, string, IFormatProvider, string> CreateConverter<T>() 
    where T : struct // not really needed 
{ 
    var method = typeof(T).GetMethod("ToString", new[] { typeof(string), typeof(IFormatProvider) }); 
    if (method == null) 
    { 
     throw new InvalidOperationException(string.Format("The type {0} does not contain a suitable ToString-method.", typeof(T).FullName)); 
    } 

    var instanceParameter = Expression.Parameter(typeof(object), "instance"); 
    var formatParameter = Expression.Parameter(typeof(string), "format"); 
    var providerParameter = Expression.Parameter(typeof(IFormatProvider), "provider"); 

    var convertedInstance = Expression.Convert(instanceParameter, typeof(T)); 
    var methodCall = Expression.Call(convertedInstance, method, formatParameter, providerParameter); 
    var lambda = Expression.Lambda<Func<object, string, IFormatProvider, string>>(methodCall, instanceParameter, formatParameter, providerParameter); 
    return lambda.Compile(); 
} 

처럼 사용할 수 있습니다 : 확인

var d = CreateConverter<MyStruct>(); 
Console.WriteLine(d(new MyStruct(), "", CultureInfo.CurrentCulture)); 

d = CreateConverter<DateTime>(); 
Console.WriteLine(d(DateTime.Now, "yyyydd", CultureInfo.CurrentCulture)); 

EDIT 그 입력이 올바른 유형 임

public static Func<T, string, IFormatProvider, string> CreateConverter<T>() 
{ 
    var method = typeof(T).GetMethod("ToString", BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(string), typeof(IFormatProvider) }, null); 
    if (method == null) 
    { 
     throw new InvalidOperationException(string.Format("The type {0} does not contain a suitable ToString-method.", typeof(T).FullName)); 
    } 

    var instanceParameter = Expression.Parameter(typeof(T), "instance"); 
    var formatParameter = Expression.Parameter(typeof(string), "format"); 
    var providerParameter = Expression.Parameter(typeof(IFormatProvider), "provider"); 

    var methodCall = Expression.Call(instanceParameter, method, formatParameter, providerParameter); 
    var lambda = Expression.Lambda<Func<T, string, IFormatProvider, string>>(methodCall, instanceParameter, formatParameter, providerParameter); 
    return lambda.Compile(); 
} 
+0

잘 보입니다.델리게이트 (현재 객체)의 입력 매개 변수가 항상 올바른 유형 (DateTime 등)인지 확인하는 것이 좋을 것입니다! :) –

+0

@MartinMulder 물론 할 수 있습니다. 그냥'object'를'T'로 대체하십시오. 'T '로의 변환은 더 이상 필요하지 않습니다. 내 편집을 참조하십시오. –

관련 문제