【问题标题】:Calling CreateInstance causes thread error调用 CreateInstance 导致线程错误
【发布时间】:2013-05-01 13:35:44
【问题描述】:

我创建了小型便携式库(reference,目标:Windows、Windows 8、Windows Phone 7.5) 用于教育目的。我决定在我的小型 Windows 8 Metro 风格应用程序中使用它。不幸的是,当我从库中调用方法时,抛出异常:

应用程序调用了一个为不同线程编组的接口。

在以下行:

return Activator.CreateInstance(outputType, constructorArguments.ToArray());

(Resolve method) outputTypetypeof(ClassFromMyMetroStyleApp)。 库作为 dll 引用添加到项目中。

我可以做些什么来解决这个问题?

编辑: 方法是从 Metro Style App 解决方案中的 UnitTest 调用:

[TestClass]
public class ResolvingTypesTests
{
    /// <summary>
    /// The school context interface test.
    /// </summary>
    [TestMethod]
    public void SchoolContextTest()
    {
        var schoolContext = TypeService.Services.Resolve<ISchoolContext>();

        Assert.AreEqual(typeof(SchoolCollection), schoolContext.GetType());
    }
}

其中TypeService是静态类,Services是IResolvable类型的静态属性(接口由Library提供)。

服务属性:

/// <summary>
    /// The resolvable.
    /// </summary>
    private static IResolvable resolvable;

    /// <summary>
    /// Gets the type services.
    /// </summary>
    public static IResolvable Services
    {
        get
        {
            if (resolvable == null)
            {
                var builder = new ContainerBuilder();
                builder.Register();
                resolvable = builder.Build();
            }

            return resolvable;
        }
    }

【问题讨论】:

  • ClassFromMyMetroStyleApp 是 UI 类吗? constructorArguments 是什么?
  • 这是一个 COM 编组错误,在商店应用中大量使用。原因尚不清楚,但您需要告诉测试运行程序初始化正确运行测试的线程的可能性很高。这是一个讨论相同问题的sample question
  • 哇,谢谢!我去看看。

标签: c# .net reflection


【解决方案1】:

当您在一个线程中使用在另一个线程中创建的某些对象(通常是 UI 对象)时,您可能会在单线程单元中遇到此错误。

【讨论】:

  • ClassFromMyMetroStyleApp 是仅实现 ISchoolProvider 的简单类(并且没有基类型)。 constructorArguments 是 ClassFromMyMetroStyleApp 参数实例的数组。在这种情况下,该数组为空(ClassFromMy.. 具有无参数构造函数)。
  • 对不起,我的意思是 ISchoolContext,而不是 ISchoolProvider :-)
【解决方案2】:

找到解决方案(感谢 Hans Passant 提供线索!) 需要给测试方法添加一个属性:

[UITestMethod]

【讨论】:

    【解决方案3】:

    不仅因为跨线程访问,还有性能原因,不鼓励使用Activator。 http://bloggingabout.net/blogs/vagif/archive/2010/04/02/don-t-use-activator-createinstance-or-constructorinfo-invoke-use-compiled-lambda-expressions.aspx

    这里作者提供了 Activator 和使用 Lambda 表达式实例化对象的对比。 我为您将代码包装在一个方法中。试试这个

    public object CreateObject(Type type)
        {
    
            var ctor = type.GetConstructor(new Type[]{});
            // Make a NewExpression that calls the ctor with the args we just created
            NewExpression newExp = Expression.New(ctor, null);
    
            // Create a lambda with the New expression as body and our param object[] as arg
            LambdaExpression lambda = Expression.Lambda(newExp, null);
    
            // Compile it
            var compiled = lambda.Compile();
            if (compiled != null)
            {
            }
            return compiled.DynamicInvoke();
        }
    

    【讨论】:

    • 不太确定这如何适用于该问题。您的参考资料没有详细说明这将如何避免跨线程异常,而且它适用于编译表达式——这不是 OP 使用的。
    • 投反对票?我只是提出了一种替代方法来实例化对象,它比激活器更好并且不会产生跨线程异常
    • 我觉得值得一试。我稍后再检查(5-6 小时,我现在不在家)。
    • 很遗憾,代码不起作用 - LambdaExpression 没有 Compile() 方法。
    • 我发现,可移植类库不支持编译方法。没有 FormatterServices。需要使用 CreateInstance 并摆脱错误。
    猜你喜欢
    • 2012-04-26
    • 2015-06-01
    • 1970-01-01
    • 2021-02-06
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 2019-02-03
    • 1970-01-01
    相关资源
    最近更新 更多