0

SGEN を使用してシリアライゼーション アセンブリをプリコンパイルするプロジェクトがあります (/proxytypes フラグなし)。このプロジェクトでは、これまで内部にあったクラスが存在します (したがって、sgen はそれをそのままにしておきます)。クラスをパブリックにする必要がありますが、そうするだけで sgen が次のエラーで失敗します。

タイプ 'Infragistics.Shared.DisposableObject' は、参照されていないアセンブリで定義されています...'

このアセンブリは実際に参照されており、常に参照されています。参照されていない場合、アセンブリ自体はコンパイルされません。バージョンも正確に一致し、参照では特定のバージョンがオフになっています。

最初の紛らわしい部分は、このクラスには public 状態がない (public フィールドもプロパティもまったくない) ことです。これは、シリアル化の適切な候補にはなりません。

さらに紛らわしいのは、唯一無二のパブリック (ジェネリック) メソッドの where 句を削除すると、sgen がアセンブリを適切に処理できるようになることです。

これは、明示的に実装されていない公開された唯一のものを持つクラスです(インターフェイスには2つのメソッドが実装されていますが、関係ありません):

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 は、失敗したときに sgen が見つけられないタイプである DisposableObject から継承します。where 句をコメントアウトすると、UIElement はまだ別の場所で使用されていますが、sgen はそれについて不満を抱いていません。Support() メソッドを internal とマークすると、sgen は公開されているものだけを処理するため、sgen も完了できます。

そもそも、sgen が Web サービス以外のパブリック メソッドを気にするのはなぜでしょうか。

where句の存在だけでつまずくのはなぜですか?

この特定のケースで、アセンブリが明らかに存在するのに、sgen によってアセンブリが見つからないのはなぜですか?

4

1 に答える 1

2

これでいくつかのテストを行い、使用できる可能性のある回避策を見つけました。

これは、派生した型を持たないアセンブリから型 (または where 句によって参照される型の基本型) を参照する where 句を持つジェネリック メソッドがある場合に再現できることがわかりました。現在のアセンブリで。

たとえば、私が見つけた問題の最も簡単な再現は次のとおりです。

次の C# コードを含む Class Library One:

namespace One
{
    public class BaseObject
    {
    }
}

次の C# コードを含むクラス ライブラリ 2:

using One;

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

        }        
    }
}

Two.dll で sgen を使用すると、アセンブリ One が参照されていないというエラーが再現されます。

回避策として、アセンブリ (クラス ライブラリ) 2 の任意のクラスをアセンブリ 1 のクラスから派生させるか、アセンブリ 1 からインターフェイスを実装できることがわかりました。特定のケースでこれを回避するには、次のクラスを追加できます。

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

あなたが尋ねた 3 つの質問に対する回答は実際には見つかりませんでしたが、実際のエラーは 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: 

上記のアセンブリ 1 と 2 を参照し、次のコードを使用して、この参照アセンブリを再現できました。

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

前に提案した回避策と同様に、アセンブリ 1 のクラスから派生する 2 番目の型を追加すると、例外を回避できます。

アセンブリ 2 に必要な追加のクラス:

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);
于 2012-08-05T04:28:27.877 に答える