SGEN未通过公共通用方法的where子句

时间:2012-06-12 17:27:11

标签: c# .net serialization sgen

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

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

这个程序集确实被引用,并且总是有,否则程序集本身就不会编译。版本也完全匹配,并且引用已关闭特定版本。

第一个令人困惑的部分是这个类没有公共状态(没有公共字段,根本没有属性),这使它不适合序列化。

更令人困惑的是,删除one-only-only public(generic)方法中的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会首先关注非webservices公共方法?

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

为什么sgen在这种特殊情况下没有找到装配体?显然在那里?

1 个答案:

答案 0 :(得分:1)

我做了一些测试,发现了一个可能的解决方法,你可以使用。

我发现如果你的泛型方法有一个where子句引用一个类型(或者where子句引用的类型的基类型)来自你没有任何组件的程序集,我发现这可以重现从当前程序集派生的类型。

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

类库1包含以下C#代码:

namespace One
{
    public class BaseObject
    {
    }
}

类库2,带有以下C#代码:

using One;

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

        }        
    }
}

在Two.dll上使用sgen时,会再现错误,它会抱怨程序集One没有被引用。

对于一种解决方法,我发现我可以从程序集中的类(类库)中派生出两个类,或者从程序集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: 

我能够从上面重现这个引用程序集One和Two并使用以下代码:

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);