동적 매개 변수 및 제네릭으로 확장 메서드를 호출 할 수 없습니다.

c# dapper dynamic extension-methods generics

문제

다른 사람들이이 같은 문제를 겪고 있는지 궁금합니다. Dapper를 프로젝트 용 ORM에 사용하고 IDbConnection 인터페이스에서 내 확장 메서드 중 일부를 만들어 코드를 단순화하고 어디에서 실행했는지 궁금합니다. (내가 뭘 발견했는지) 수수께끼 같은 실수로.

나는 그 과정을 밟을 것이다.

첫째, 확장 메서드를 DbExtensions 라는 정적 클래스의 프로젝트에 DbExtensions 과 같이 추가했습니다.

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

이렇게하면 다음 설명과 함께 컴파일 오류가 발생합니다.

'System.Data.IDbConnection' has no applicable method named 'Query' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

이것은 문제가되지 않으며 오류를 수정하는 방법을 알려주기 때문에 오류가 실제로 도움이됩니다. 그래서 나는 다음을 시도한다.

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

그것을 올바르게 컴파일합니다. 이상한 일이 일어나고 있습니다. Visual Studio에서 IEnumerable<T> 이어야 하는 SqlMapper.Query<T> 의 반환 값을 SqlMapper.Query<T> 조작하려고하면 Visual Studio는 object 를 통해 상속 된 속성을 제외하고 인텔리 센스 속성을 제공하지 않습니다.

인텔리 센스가 알아낼 정도로 똑똑하지 않다는 것을 생각하고 있습니다. 저는 실제로 코드를 실행하려고 시도 할 때까지 저의 즐거운 길을 간 것입니다.

내가 그것을 실행하려고하면, 그것은 다음과 같은 오류가있는. .First() 를 호출하는 곳에서 위로 올라갑니다.

'System.Collections.Generic.List<MyNameSpace.MyClass>' does not contain a definition for 'First'

이제이 오류는 흥미로웠다 고 생각했습니다 ... 잠시 머리를 숙이고 나는 첫 번째 주장이 동적 타이핑에 대해 불평하고 있다는 것을 깨달았습니다.

컴파일러는 일반 템플릿을 작성할 수 없기 때문에 쿼리가 IEnumerable<T> 을 반환한다는 것을 모르기 때문에이 오류가 발생한다고 가정합니다 (DLR에서 실행 됨)? 나는 누군가 지식이있는 이것을 설명하는 것을 듣고 싶다. 본질적으로 그것을 고칠 수있는 두 가지 방법을 찾았습니다 :

  • dynamic 매개 변수를 object 캐스트
  • 반환 된 값을 IEnumerable<T>

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

using System.Collections.Generic;
using System.Data;
using System.Linq;

public static class DbExtensions
{
    public static T Scalar<T>(
        this IDbConnection cnn, string sql, dynamic param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null)
    {
        var ret = SqlMapper.Query<T>(cnn, sql, param, transaction, buffered, commandTimeout, commandType).First();
        return ret;
    }
}

요약하자면:

나는 DLR의 qwerks를 작업하는 것에 익숙하지 않으며 동적 + Generics로 주위를 망칠 때 염두에 두어야 할 몇 가지 경고가있는 것 같습니다 ...?

나는 이것이 하나의 질문이 아니라는 것을 안다. 그러나 실제로이 글을 쓰기 시작했을 때 나는 무슨 일이 일어나고 있는지를 알지 못했고 그 과정에서 그것을 알아 냈다! 비슷한 문제가있는 다른 사람을 도울 것이라고 생각했는데 ...

수락 된 답변

제안대로, 나는 실제 답변에서 내 질문에 대답 하려고 노력할 것이다 ... (이제 8 시간이되었다)

문제에 대한 나의 이해는 다음과 같습니다.

  • 참조 된 질문에 설명 된대로 동적 유형에는 사용할 수있는 확장 메서드가 없지만 확장 메서드는 this 키워드가없는 것처럼 ( 인스턴스 메서드로) 일반적으로 사용할 수 있습니다.

예 :

public static Enumerable<T> ExtensionMethod(this ExtendedObject p1, dynamic p2) {
    //Do Stuff
}

dynamic y = something;
var x = new ExtendedObject();

//this works
var returnedEnumerable = x.ExtensionMethod(y); 

//this doesn't work
var returnedValue = x.ExtensionMethod(y).SomeEnumerableExtensionMethodLikeFirst() 

Jon Skeet 은이 대답 에서 지적했듯이 이것은 설계 상 및 DLR 구현의 일부입니다. 호출에 동적 인수가있는 경우 동적으로 간주되는 반환 유형이 있습니다.

  • 비슷한 이유로, 확장 메소드에서 동적 변수를 사용하는 것은 다소 불안정합니다 ...

public static Enumerable<T> ExtensionMethod(this ExtendedObject p1, dynamic p2) {
    //Do Stuff
}

dynamic y = something;
var x = new ExtendedObject();

//this works
var returnedEnumerable = x.ExtensionMethod(y); 

//this doesn't work
var returnedValue = x.ExtensionMethod(y).SomeEnumerableExtensionMethodLikeFirst() 

위의 예제가 작동하도록하려면 다음 중 하나를 수행하십시오.

public static Enumerable<T> ExtensionMethod(this ExtendedObject p1, dynamic p2) {
    //Do Stuff
}

dynamic y = something;
var x = new ExtendedObject();

//this works
var returnedEnumerable = x.ExtensionMethod(y); 

//this doesn't work
var returnedValue = x.ExtensionMethod(y).SomeEnumerableExtensionMethodLikeFirst() 



아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.
아래 라이선스: CC-BY-SA with attribution
와 제휴하지 않음 Stack Overflow
이 KB는 합법적입니까? 예, 이유를 알아보십시오.