【问题标题】:SGEN fails on where clause of public generic methodSGEN 在公共泛型方法的 where 子句上失败
【发布时间】:2012-06-12 17:27:10
【问题描述】:

我有一个项目,其中 SGEN 用于预编译序列化程序集(没有 /proxytypes 标志)。在这个项目中,有一个到目前为止一直是内部的类(因此 sgen 将不理会它)。我需要公开课程,这样做的简单行为会导致 sgen 失败并出现错误:

“Infragistics.Shared.DisposableObject”类型在未引用的程序集中定义...'

这个程序集确实被引用了,并且一直都有,否则程序集本身将无法编译。版本也完全匹配,并且引用已关闭特定版本。

第一个令人困惑的部分是这个类没有公共状态(没有公共字段,根本没有属性),这并不使它成为序列化的良好候选者。

更令人困惑的部分是删除唯一公共(通用)方法上的 where 子句允许 sgen 很好地处理程序集。

这是一个类,上面只有一个公共的、非显式实现的东西(接口实现了两个方法,不相关):

public class AppointmentDrawFilter : IUIElementDrawFilter
{
    // This is a fluent method to register a type with its handler
    public AppointmentDrawFilter Support<TUiElement>(DrawPhase phases, Func<UIElement, Appointment> retriever = null)
        where TUiElement : UIElement  // <-- commenting out (or changing UIElement to MarshalByRefObject) fixes sgen
    {
        // adds input to a couple dictionaries (failure still occurs with body commented out)
        return this;
    }
}

注意:UIElement 继承自 DisposableObject,sgen 失败时找不到的类型。请注意,当我注释掉 where 子句时,UIElement 仍在其他地方使用,但 sgen 并没有对此感到不满。标记 Support() 方法内部也允许 sgen 完成,因为它只关心公共的东西。

为什么 sgen 会首先关心非 Web 服务的公共方法?

为什么它只会因为 where 子句的存在而绊倒?

为什么在这种特殊情况下,sgen 没有找到明显存在的程序集?

【问题讨论】:

    标签: c# .net serialization sgen


    【解决方案1】:

    我对此进行了一些测试,并找到了您可以使用的可能解决方法。

    我发现,如果您有一个泛型方法,该方法有一个 where 子句从您没有的程序集中引用类型(或 where 子句引用的类型的基类型),则可以重现这种情况从当前程序集中派生的类型。

    例如,我发现的问题的最简单再现是:

    具有以下 C# 代码的类库一:

    namespace One
    {
        public class BaseObject
        {
        }
    }
    

    具有以下 C# 代码的类库二:

    using One;
    
    namespace Two
    {
        public class TestClass
        {
            public void TestMethod<T>()
                where T : BaseObject
            {
    
            }        
        }
    }
    

    在 Two.dll 上使用 sgen 时,会重现错误,它抱怨未引用程序集 One。

    对于一种解决方法,我发现我可以从程序集一中的类派生程序集(类库)二中的任何类,或者从程序集一中实现接口。要在您的特定情况下解决此问题,您可以添加以下类:

    using Infragistics.Shared;
    namespace DayViewTextCenter
    {
        public class WorkaroundSgenIssue:DisposableObject
        {
            protected override void OnDispose()
            {
            }
        }
    }
    

    虽然我实际上没有找到您提出的三个问题的答案,但我确实发现实际错误是 System.Xml.Serialization.Compiler 类的 Compile 方法中的 System.InvalidOperationException:

    System.InvalidOperationException occurred
      Message=Unable to generate a temporary class (result=1).
    error CS0012: The type 'One.BaseObject' is defined in an assembly that is not referenced. You must add a reference to assembly 'One, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
    
      Source=System.Xml
      StackTrace:
           at System.Xml.Serialization.Compiler.Compile(Assembly parent, String ns, XmlSerializerCompilerParameters xmlParameters, Evidence evidence)
      InnerException: 
    

    我能够从上面复制这个引用程序集一和二,并使用以下代码:

    Type type = typeof(TestClass);
    Assembly assembly = type.Assembly;
    XmlReflectionImporter importer = new XmlReflectionImporter();
    XmlTypeMapping mapping = importer.ImportTypeMapping(type);
    CompilerParameters parameters = new CompilerParameters();
    Assembly xmlAssembly = XmlSerializer.GenerateSerializer(new Type[] { type }, new XmlMapping[] { mapping }, parameters);
    

    就像我之前建议的解决方法一样,如果添加派生自程序集 One 中的类的第二种类型,则可以避免异常。

    组装二需要额外的类:

    public class Test : BaseObject
    {
    }
    

    更新了生成序列化程序集的逻辑:

    Type type = typeof(TestClass);
    Assembly assembly = type.Assembly;
    XmlReflectionImporter importer = new XmlReflectionImporter();
    XmlTypeMapping mapping = importer.ImportTypeMapping(type);
    Type type2 = typeof(Test);
    XmlReflectionImporter importer2 = new XmlReflectionImporter();
    XmlTypeMapping mapping2 = importer2.ImportTypeMapping(type2);
    CompilerParameters parameters = new CompilerParameters();
    Assembly xmlAssembly = XmlSerializer.GenerateSerializer(new Type[] { type, type2 }, new XmlMapping[] { mapping, mapping2 }, parameters);
    

    【讨论】:

    • 不幸的是,包含在 8.0A 版 Windows SDK 中的 SGEN 版本似乎已经解决了我遇到的问题,并且在升级之前我无法测试您的建议。感谢您的回复,sgen 标签在这里很少受到关注。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 2019-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多