Динамическое приведение к универсальному типу - PullRequest
5 голосов
/ 23 марта 2012

Просто быстрый прием до наступления выходных ...

У меня есть метод со следующей подписью, который мне нужно вызвать:

public interface IObjectProvider<T>
{
    T Get(Predicate<T> condition);
}

Это даст мнеT из любого источника, который соответствует критерию предиката.

Теперь это нужно вызывать из контекста, где все, что у меня есть, это:

//the actual predicate that's going to be evaluated
var predicate = predicateProperty.GetValue(invocation.InvocationTarget, null);

//The type that should go into the call as type param
Type relationTargetType = relationDefinition.RelatedType;

Как выМожно предположить, что компилятор не позволит мне использовать переменную predicate в качестве параметра.Что мне нужно сделать, это преобразовать этот объект в предикат, но параметры общего типа должны быть постоянными во время компиляции, так что это не сработает.

Я начал возиться с этим, но безуспешнодо сих пор:

Type genericPredicateType = typeof(Predicate<>);
Type specificPredicateType= genericPredicateType.MakeGenericType(relationTargetType);
Convert.ChangeType(predicate, specificPredicateType)

Как же я могу сделать это?

РЕДАКТИРОВАТЬ: Я думал, что это был вопрос, не зависящий от варианта использования, но, очевидно,Я был неправ.Итак, поскольку существует такая ажиотаж в отношении того, что я делаю, что у меня есть, почему, и еще чего, вот еще много дополнительной информации.Я пытаюсь разрешить отношения между объектами в прокси (Castle Dynamic Proxy).Следующий фрагмент кода должен объяснить тип отношения, которое я хочу изобразить:

public class Order
{
    public virtual int Id { get; set; } // OR-Mapped
    public virtual DateTime OrderDate { get; set; } // OR-Mapped

    [RelatedObject(typeof(Address), "DeliveryAddressPredicate")]
    public virtual Address DeliveryAddress { get; set; }

    public Predicate<Address> DeliveryAddressPredicate
    {
        get { return new Predicate<Address>(a => OrderDate >= a.ValidFrom && OrderDate <= a.ValidTo); }
    }
}

public class Address
{
    public virtual DateTime ValidFrom { get; set; } // OR-Mapped
    public virtual DateTime ValidTo { get; set; } // OR-Mapped

    //Not OR-Mapped
    [RelatedList(typeof(Order), "OrdersPredicate")]
    public virtual IList<Order> Orders { get; set; }

    public Predicate<Order> OrdersPredicate
    {
        get { return new Predicate<Order>(o => o.OrderDate >= ValidFrom && o.OrderDate <= ValidTo); }
    }

Подводя итог, предполагается, что он станет Fuzzy OR-Mapping, предназначенным для расширения NHibernate в одном или двух проектах.

Как я хотел заставить это работать?Адрес проксируется, и когда выполняется вызов свойства с одним из моих пользовательских атрибутов, я использую интерфейс IInterceptor DynamicProxy, чтобы разрешить отношение.Основная проблема заключается в том, что это разрешение должно происходить в методе IInterceptor.Intercept (), который имеет только один параметр ( см. Здесь ), и у меня нет доступных параметров универсального типа.Итак, в конце концов все сводится к простому вопросу .Net: у меня Type хранится в переменной и Method, который должен вызываться с параметром общего типа вышеупомянутого типа ...

Извините за любые допущенные ошибки (например, вызов var a Type - грубый человек), это был целый день; -)

Ответы [ 3 ]

8 голосов
/ 23 марта 2012

У вас есть IObjectProvider<T>.Если T является типом, известным во время компиляции, вы можете просто использовать приведение.Например, если T было Foo:

IObjectProvider<Foo> provider = …;
var predicate = (Predicate<Foo>)predicateProperty.GetValue(
    invocation.InvocationTarget, null);
Foo item = provider.Get(predicate);

РЕДАКТИРОВАТЬ: Кажется, вы не знаете T во время компиляции.Это означает, что у вас есть два варианта:

  1. Использование dynamic:

    object provider = …
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    object item = ((dynamic)provider).Get((dynamic)predicate);
    
  2. Использование отражения:

    object provider = …;
    object predicate = predicateProperty.GetValue(
        invocation.InvocationTarget, null);
    var getMethod = provider.GetType().GetMethod("Get");
    object item = getMethod.Invoke(provider, new[] { predicate });
    
1 голос
/ 23 марта 2012

В этом вопросе много путаницы с типами, var и т. Д.

Это бессмысленное предложение

Оно имеет тип var, и GetValue превратило его в объект.

Я думаю, что вы говорите

У меня есть код, который нуждается в Predicate<T>

У вас есть код (который вы не делаетепокажи нам), который возвращает Object.И хочу как-то привести это возвращаемое значение в Predicate<T>.Если возвращенный объект - Predicate<T>, просто перейдите на (Predicate<T>)retobj - и все готово.Если это не тип, который может быть приведен к Predicate<T>, то никакое количество покачиваний не превратит его в Predicate<T>.

0 голосов
/ 17 февраля 2015

Я делаю так

public T CastToType<T>(object objType, T type) where T : class
    {
        var cast = objType as T;

        if(cast == null)
            throw new InvalidCastException();

        return cast;
    }

И вот так

var test = CastToType(objType, new ArrayList());

тест будет иметь тип ArrayList

...