如何将命令对象转换为其通用接口?

时间:2013-09-20 16:36:25

标签: c# generics

我有一个可以实现ICommand但可以实现通用接口IUpdateAggregateCommand<TAggregate>的命令对象。

public interface IUpdateAggregateCommand<TAggregate> : ICommand where TAggregate : IAggregate
{
    TAggregate Entity { get; set; }
}

我正在测试这样:

    var isIUpdateAggregateCommand = command.GetType().GetInterfaces().Any(x =>
        x.IsGenericType &&
        x.GetGenericTypeDefinition() == typeof(IUpdateAggregateCommand<>));

如果确实实现了界面,我该如何将其转换为特定类型,例如如果它实现了IUpdateAggregateCommand<Person>,我该如何将命令强制转换为IUpdateAggregateCommand<Person>

我需要能够设置实体的值

更新

我在装饰器内部,我不知道我需要将它投射到的聚合的类型。所以我需要弄清楚它是什么类型然后把它投射到那个

4 个答案:

答案 0 :(得分:3)

你不能直接转换吗?

IUpdateAggregateCommand<MyAggregate> updateAggregateCommand = command as IUpdateAggregateCommand<MyAggregate>;
if (updateAggregateCommand != null)
{
    updateAggregateCommand.Entity = ...
}

MyAggregate是您定义的类型(显然)。

修改

我认为不可能扫描已实现的接口并简单地转换为它们。反思可能是这类工作的最佳解决方案。您可以扫描已实现的接口,然后进行动态方法调用以设置实体。然后,您需要知道实体的类型并相应地实例化或设置它。听起来不太安全。

你想要完成什么?你的装饰师是如何实施的?如果这种方法很麻烦,也许有其他解决方案来解决你的问题。

答案 1 :(得分:2)

您能检查一下您的命令变量是否属于该类型?如果在实例化此命令对象时,它继承自它,则返回true。

if(command is IUpdateAggregateCommand<TAggregate>)

然后你就会:

var newCommand = ((IUpdateAggregateCommand<TAggregate>)command);

var newCommand = command as IUpdateAggregateCommand<TAggregate>;

如果您的更新不知道要将其转换为什么,您可以继续使用速度慢的反射,或执行快速,可读的If, Else If检查,并且您将需要使用某些特殊属性/功能,无论如何都是这种类型的独特之处。 如果您正在寻找 公共属性 ,那么您需要创建一个更通用的接口,这些接口都是从它们继承的,此时您不需要If / Else无论如何。


第二次编辑: 你在寻找像下面这样的概念吗?这允许我根据类型从列表中获取项目,并根据其泛型类型返回它。

    List<IMockEvent> events = new List<IMockEvent>();
    public IMockEvent<K> GetMockEvent<T, K>()
    {
        return events.First(t => t is T) as IMockEvent<K>;
    }
    public void Add(IMockEvent evt)
    {
        events.Add(new MockStatusUpdate());
    }

其中类定义为

public class EMockStatusUpdated : StatusUpdated, IMockEvent<string> { }
public interface IMockEvent<T> : IMockEvent { }
public interface IMockEvent { }

答案 2 :(得分:1)

您可以使用反射来执行此操作:

public static class Extensions
{
    private static readonly MethodInfo SetAggregateInternalMethod = typeof(Extensions)
        .GetMethod("SetAggregateInternal", BindingFlags.Static | BindingFlags.NonPublic);

    private static void SetAggregateInternal<TAggregate>(object item, TAggregate value) where TAggregate : IAggregate
    {
        var aggregateCommand = item as IUpdateAggregateCommand<TAggregate>;
        if (aggregateCommand != null)
            aggregateCommand.Entity = value;
    }

    public static void TrySetAggregate(object item, IAggregate value)
    {
        SetAggregateInternalMethod
            .MakeGenericMethod(value.GetType())
            .Invoke(null, new[] { item, value });
    }
}

您还可以使用缓存并编译Expression来提高性能。

答案 3 :(得分:1)

public interface IAggregate { }
public class Person : IAggregate { }

public interface ICommand { }
public class BaseCommand : ICommand { }

public interface IUpdateAggregateCommand<out T> : ICommand where T : IAggregate
{
    T GetEntity();
}

public class UpdateAggregateCommand<T> : IUpdateAggregateCommand<T> where T : IAggregate
{
    private T entity;
    public void SetEntity(T t) { this.entity = t; }

    public T GetEntity() { return this.entity; }
}


class Program
{
    static void Main(string[] args)
    {
        var command = new BaseCommand();
        var obj = command as IUpdateAggregateCommand<IAggregate>;
        if (obj != null)
            Console.WriteLine(obj.GetEntity().GetType());

        var command1 = new UpdateAggregateCommand<Person>();
        command1.SetEntity(new Person());
        var obj1 = command1 as IUpdateAggregateCommand<IAggregate>;
        if (obj1 != null)
            Console.WriteLine(obj1.GetEntity().GetType());
    }
}