转换动态对象并传递到UnitOfWork和Repository模式.抛出异常

the*_*ton 7 c# unit-of-work repository-pattern expandoobject dynamicobject

这是一个非常具体的问题.不太确定如何说出来.基本上我正在实现工作单元和存储库模式,我有一个动态对象,我转换为int,但如果我使用var它将在尝试调用方法时抛出异常.

我试图删除所有这些问题,我可以解决这个问题.出于某种原因,我只看到这两种设计模式.我得到的例外是Additional information: 'BlackMagic.ITacoRepo' does not contain a definition for 'DoStuff'

这是代码:

class BlackMagic
{
    static void Main(string[] args)
    {
        dynamic obj = new ExpandoObject();
        obj.I = 69;

        UnitOfWork uow = new UnitOfWork();

        int i1 = Convert.ToInt32(obj.I);
        var i2 = Convert.ToInt32(obj.I);

        if(i1.Equals(i2))
        {
            uow.TacoRepo.DoStuff(i1); // Works fine
            uow.TacoRepo.DoStuff(i2); // Throws Exception
        }
    }
}

class UnitOfWork
{
    public ITacoRepo TacoRepo { get; set; }

    public UnitOfWork()
    {
        TacoRepo = new TacoRepo();
    }
}

class Repo<T> : IRepo<T> where T : class
{
    public void DoStuff(int i)
    {
    }
}

interface IRepo<T> where T : class
{
    void DoStuff(int i);
}

class TacoRepo : Repo<Taco>, ITacoRepo
{
}

interface ITacoRepo : IRepo<Taco>
{
}

class Taco
{
}
Run Code Online (Sandbox Code Playgroud)

编辑:我试图找到答案的主要问题是,为什么通过调用DoStuff工作单元(使用repo时)调用异常,但如果在BlackMagic类中存在DoStuff则不会抛出异常.

Vla*_*kov 3

这是我 5 年前向 Microsoft 报告的错误之一,就在dynamic。据我所知,它在他们的列表中被认为是非常低的优先级,并且可能永远不会被修复。

以下是简单的重现步骤:

using System.Collections;

class C
{
    static void Main()
    {
        object[] array = { };
        IList list = new ArrayList();
        list.CopyTo(array, 0); // Works okay
        dynamic index = 0;
        list.CopyTo(array, index); // Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'System.Collections.IList' does not contain a definition for 'CopyTo'
    }
}
Run Code Online (Sandbox Code Playgroud)

这是问题的解释。当对静态类型为接口类型的表达式调用函数成员(方法或索引器)时,并且调用的至少一个参数属于该类型dynamic(这意味着完整的成员查找——类型推断—— - 重载解析过程被推迟到运行时,并成为运行时绑定器而不是编译器的责任;编译器仅根据不完整的类型信息执行部分检查),并且被调用的成员由接口继承如果从其基接口之一(而不是在接口本身中声明),则运行时绑定程序无法正确遍历基接口树以查找继承的成员,并在运行时引发异常,报告所需的成员不是成立。请注意,这只是运行时绑定器的错误——编译器正确地接受了调用(但会拒绝它,例如,如果您在方法名称中输入了拼写错误)。

可能的解决方法:将调用成员的表达式强制转换为实际声明您尝试调用的成员的基接口。例如,上述重现步骤中的程序可以修复如下:

using System.Collections;

class C
{
    static void Main()
    {
        object[] array = { };
        IList list = new ArrayList();
        list.CopyTo(array, 0); // Works okay
        dynamic index = 0;
        ((ICollection) list).CopyTo(array, index); // Works okay
    }
}
Run Code Online (Sandbox Code Playgroud)

dynamic或者,如果可能的话,通过将类型参数强制转换为被调用成员签名中指定的类型来完全摆脱动态分派。

using System.Collections;

class C
{
    static void Main()
    {
        object[] array = { };
        IList list = new ArrayList();
        list.CopyTo(array, 0); // Works okay
        dynamic index = 0;
        list.CopyTo(array, (int) index); // Works okay
    }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,如果您确实希望在运行时发生重载解析,那么这两种解决方法可能都没有帮助,并且在可能的候选者中,既有接口声明的成员,也有接口继承的成员。在这种情况下,您可能需要发明一些临时解决方案,或者显着重构您的程序。