リフレクションを使用してオブジェクトのパブリックまたはプライベート フィールドを再帰的にクロールして XML として保存し、後で再構築する XML シリアライザーを作成しています。ポインタと、そうすることで、マネージド/アンマネージド境界を越え、(ありがたいことに) メモリを混乱させる代わりにクラッシュしました。この問題の解決策を見つける必要がありますが、アンマネージ コードのバックグラウンドがないため、やや迷っています。
ポインターまたは参照の値はメモリアドレスであるため、ポインターまたは参照を実際にそのままシリアル化することはできず、ポインターを再インスタンス化するときに正しいオブジェクトがそのアドレスにあるとは期待できません。 XML。私が理解しているように、この問題の原因となるオブジェクトを検出して無視するか、ポイントされているオブジェクトを見つけてシリアル化し、逆シリアル化時にそのオブジェクトを逆シリアル化し、そのオブジェクトの場所にポインターを向ける必要があります。しかし、どうすればよいかわかりません。私の最初の推測では、Type.IsPointer でフィルタリングしても問題は解決しなかったようです。私が求めていることはできますか?より良い解決策はありますか?戦略的なアンマネージ コードでこれを行うことはできますか?
コンテキスト: 通常の XmlSerializer ではできない型 (IDictionary、循環参照を持つ型など) をシリアル化できるシリアライザーを作成しています。私のシリアライザーは属性と ISerializeable または IXMLSerializeable の実装を無視します。オブジェクトのすべてのフィールドをシリアル化するために、いくつかのルールを再帰的にやみくもに使用します。動作しますが、一部のオブジェクトでネイティブ/マネージド境界にぶつかっています。オブジェクトが常に変更されており、オブジェクトのバージョンの競合をバイナリ シリアル化で解決する方法がわからないため、バイナリ シリアル化を使用していません。
編集:これは、「System.Globalization.TextInfo」クラスを再インスタンス化しようとするとクラッシュするコードです。これは、DataTable のどこかに深く埋め込まれたカルチャ オブジェクトの一部であると思います。これらの関数は、初期型パラメーターが再インスタンス化されるまで (常に ReInstantiateValueInstance から開始して) 相互に再帰的に呼び出します。
System.Globalization.TextInfo(CultureInfo) を再インスタンス化すると、「bestCtor.Invoke(parameters.ToArray())」でマネージド/ネイティブ境界例外がスローされます。
protected object ReCreateTypeWithParameters(Type t)
{
if (t.ToString() == "System.Type") return typeof(object); //we dont know the type of type
var construct = StoreUtilities.GetConstructors(t); //gets any and all constructors for an object
if (construct != null && construct.Count > 0)
{
var leastParams = (from c in construct
select c.GetParameters().Count()).Min();
var bestCtor = (from c in construct
where c.GetParameters().Count() == leastParams
select c).FirstOrDefault(); //the best constructor has the least parameters - less can go wrong
if (bestCtor != null)
{
List<object> parameters = new List<object>();
foreach (var param in bestCtor.GetParameters())
{
parameters.Add(ReInstantiateValueInstance(param.ParameterType));
}
return bestCtor.Invoke(parameters.ToArray()); //pointer types go boom here.
}
}
return null;
}
protected virtual object ReInstantiateValueInstance(Type t)
{
try
{
if (t.ToString() == "System.Type") //we don't know the Type of Type
{
return typeof(object);
}
var construct = StoreUtilities.GetConstructors(t, true); //gets an object's parameterless constructors
if (construct == null && t.IsGenericType) //no constructor, it's generic
{
object generic = ReCreateGenericType(t);
if (generic == null) //if the generic type had no constructor, we use the activator.
{
return Activator.CreateInstance(t);
}
else
{
return generic;
}
}
if (construct == null || construct.Count() == 0) //we have no constuctor. Try and make a placeholder object anyways.
{
return ReCreateTypeWithParameters(t);
}
object o = construct.First().Invoke(null);
return o;
}
catch
{
return null;
}
}
protected object ReCreateGenericType(Type t)
{
try
{
if (Type.IsGenericType != true) return null;
var construct = StoreUtilities.GetConstructors(Type, false);
if (construct != null && construct.Count() > 0)
{
construct = construct.OrderBy(i => i.GetParameters().Count()).ToList();
var tParams = construct[0].GetParameters();
List<object> paramList = new List<object>();
foreach (var p in tParams)
{
if (StoreUtilities.CanStoreAsString(p.ParameterType) == true)
{
object o = Activator.CreateInstance(p.ParameterType);
paramList.Add(o);
}
else
{
paramList.Add(ReInstantiateValueInstance(p.ParameterType));
}
}
return construct[0].Invoke(paramList.ToArray());
}
else
{
return Activator.CreateInstance(t);
}
}
catch
{
return null;
}
}