Development Tip

C # : 동적 런타임 캐스트

yourdevel 2020. 12. 3. 20:45
반응형

C # : 동적 런타임 캐스트


다음 서명으로 메서드를 구현하고 싶습니다.

dynamic Cast(object obj, Type castTo);

누구든지 그 방법을 알고 있습니까? obj는 확실히 castTo를 구현하지만 내 앱의 런타임 바인딩 항목 중 일부가 작동하도록하려면 제대로 캐스트되어야합니다.

편집 : 일부 답변이 의미가 없다면 처음에 실수로 입력했기 때문입니다 dynamic Cast(dynamic obj, Type castTo);-입력이 object또는 다른 보장 된 기본 클래스 이어야 함을 의미합니다.


여기서 캐스팅 및 변환 문제를 혼동하고 있다고 생각합니다.

  • 캐스팅 : 객체를 가리키는 참조 유형을 변경하는 행위. 객체 계층 또는 구현 된 인터페이스로 위 또는 아래로 이동
  • 변환 : 다른 유형의 원래 소스 객체에서 새 객체를 만들고 해당 유형에 대한 참조를 통해 액세스합니다.

둘 다 동일한 C # 연산자 인 캐스트를 사용하기 때문에 C #에서 2의 차이점을 아는 것은 종종 어렵습니다.

이 상황에서는 거의 확실하게 캐스트 작업을 찾지 않습니다. a dynamic를 다른 dynamic것으로 캐스팅하는 것은 본질적으로 신원 변환입니다. dynamic동일한 기본 개체에 대한 참조를 다시 가져 오기 때문에 값을 제공하지 않습니다 . 결과 조회는 다르지 않습니다.

대신이 시나리오에서 원하는 것은 전환입니다. 그것은 기본 객체를 다른 유형으로 모핑하고 결과 객체에 접근하는 dynamic방식입니다. 이를위한 최고의 API는 Convert.ChangeType.

public static dynamic Convert(dynamic source, Type dest) {
  return Convert.ChangeType(source, dest);
}

편집하다

업데이트 된 질문에는 다음 줄이 있습니다.

obj는 확실히 castTo를 구현합니다.

이 경우 Cast메서드가 존재할 필요가 없습니다. 소스 object는 단순히 dynamic참조에 할당 될 수 있습니다 .

dynamic d = source;

달성하려는 source것은 dynamic참조 통해 계층 구조에서 특정 인터페이스 또는 유형을 보는 것 입니다. 그것은 단순히 불가능합니다. 결과 dynamic참조는 구현 개체를 직접 볼 수 있습니다. 소스 계층 구조에서 특정 유형을 살펴 보지 않습니다. 따라서 계층 구조에서 다른 유형으로 캐스팅했다가 다시 돌아 오는 아이디어 는 처음에 dynamic할당하는 것과 정확히 동일합니다 dynamic. 여전히 동일한 기본 개체를 가리 킵니다.


이것은 작동합니다.

public static dynamic Cast(dynamic obj, Type castTo)
{
    return Convert.ChangeType(obj, castTo);
}

편집하다

다음 테스트 코드를 작성했습니다.

var x = "123";
var y = Cast(x, typeof(int));
var z = y + 7;
var w = Cast(z, typeof(string)); // w == "130"

PHP, JavaScript 또는 Python과 같은 언어에서 찾을 수있는 "타입 캐스팅"과 유사합니다 ( 값을 원하는 유형으로 변환 하기 때문 ). 그게 좋은지 모르겠지만 확실히 작동합니다 ... :-)


지금까지 얻은 최고 :

dynamic DynamicCast(object entity, Type to)
{
    var openCast = this.GetType().GetMethod("Cast", BindingFlags.Static | BindingFlags.NonPublic);
    var closeCast = openCast.MakeGenericMethod(to);
    return closeCast.Invoke(entity, new[] { entity });
}
static T Cast<T>(object entity) where T : class
{
    return entity as T;
}

오픈 소스 프레임 워크 Dynamitey 에는 캐스트 변환을 포함하여 DLR을 사용하여 후기 바인딩을 수행하는 정적 메서드가 있습니다 .

dynamic Cast(object obj, Type castTo){
    return Dynamic.InvokeConvert(obj, castTo, explict:true);
}

Cast<T>리플렉션을 사용하여 호출하는 것 보다 이것의 장점 IDynamicMetaObjectProvider은 동적 변환 연산자가 있는 모든 경우에도 작동한다는 것 입니다. 에 TryConvertDynamicObject .


나는 이것에 대한 답을 알고 있지만 다른 접근 방식을 사용했으며 공유 할 가치가 있다고 생각했습니다. 또한 내 접근 방식이 원치 않는 오버 헤드를 생성 할 수 있다고 생각합니다. 그러나 나는 우리가 관찰하는 부하에서 그렇게 나쁜 일을 관찰하거나 계산할 수 없습니다. 이 접근 방식에 대한 유용한 피드백을 찾고있었습니다.

역학 작업의 문제점은 동적 객체에 직접 함수를 연결할 수 없다는 것입니다. 매번 파악하고 싶지 않은 과제를 파악할 수있는 무언가를 사용해야합니다.

이 간단한 솔루션을 계획 할 때 비슷한 개체를 다시 입력하려고 할 때 유효한 중개자가 무엇인지 살펴 보았습니다. 바이너리 배열, 문자열 (xml, json) 또는 변환 하드 코딩 ( IConvertable )이 일반적인 접근 방식 이라는 것을 알았습니다 . 코드 유지 관리 요소와 게으름으로 인해 이진 변환에 들어가고 싶지 않습니다.

내 이론은 Newtonsoft 가 문자열 중개자를 사용하여 이것을 할 수 있다는 것입니다.

단점은 문자열을 개체로 변환 할 때 현재 어셈블리에서 속성이 일치하는 개체를 검색하여 리플렉션을 사용하고 형식을 만든 다음 속성을 인스턴스화하므로 더 많은 반영이 필요하다는 점을 상당히 확신합니다. 참이면이 모든 것이 피할 수있는 오버 헤드로 간주 될 수 있습니다.

씨#:

//This lives in a helper class
public static ConvertDynamic<T>(dynamic data)
{
     return Newtonsoft.Json.JsonConvert.DeserializeObject<T>(Newtonsoft.Json.JsonConvert.SerializeObject(data));
}

//Same helper, but in an extension class (public static class),
//but could be in a base class also.
public static ToModelList<T>(this List<dynamic> list)
{
    List<T> retList = new List<T>();
    foreach(dynamic d in list)
    {
        retList.Add(ConvertDynamic<T>(d));
    }
}

With that said, this fits another utility I've put together that lets me make any object into a dynamic. I know I had to use reflection to do that correctly:

public static dynamic ToDynamic(this object value)
{
    IDictionary<string, object> expando = new ExpandoObject();

    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType()))
        expando.Add(property.Name, property.GetValue(value));

    return expando as ExpandoObject;
}

I had to offer that function. An arbitrary object assigned to a dynamic typed variable cannot be converted to an IDictionary, and will break the ConvertDynamic function. For this function chain to be used it has to be provided a dynamic of System.Dynamic.ExpandoObject, or IDictionary<string, object>.


Try a generic:

public static T CastTo<T>(this dynamic obj, bool safeCast) where T:class
{
   try
   {
      return (T)obj;
   }
   catch
   {
      if(safeCast) return null;
      else throw;
   }
}

This is in extension method format, so its usage would be as if it were a member of dynamic objects:

dynamic myDynamic = new Something();
var typedObject = myDynamic.CastTo<Something>(false);

EDIT: Grr, didn't see that. Yes, you could reflectively close the generic, and it wouldn't be hard to hide in a non-generic extension method:

public static dynamic DynamicCastTo(this dynamic obj, Type castTo, bool safeCast)
{
   MethodInfo castMethod = this.GetType().GetMethod("CastTo").MakeGenericMethod(castTo);
   return castMethod.Invoke(null, new object[] { obj, safeCast });
}

I'm just not sure what you'd get out of this. Basically you're taking a dynamic, forcing a cast to a reflected type, then stuffing it back in a dynamic. Maybe you're right, I shouldn't ask. But, this'll probably do what you want. Basically when you go into dynamic-land, you lose the need to perform most casting operations as you can discover what an object is and does through reflective methods or trial and error, so there aren't many elegant ways to do this.


Alternatively:

public static T Cast<T>(this dynamic obj) where T:class
{
   return obj as T;
}

참고URL : https://stackoverflow.com/questions/4925718/c-dynamic-runtime-cast

반응형