6

我正在为我的玩具项目创建一个新的次要版本。该项目在 NuGet 上发布,与 .NET 4.0 及更高版本兼容。我介绍的一些新功能需要 .NET 4.5(用户应该能够解析.NET 4.5IReadOnlyCollection<T>IReadOnlyList<T>引入的两个接口),但我需要保持项目与 .NET 4.0 兼容,因为并非所有开发人员可以轻松迁移到最新的 .NET 框架。

所以我面临的问题是如何解决这个“前向兼容性”问题。我想过两种解决方案,但都不是很有吸引力,所以希望任何人都可以在这里给我一些想法或指导。

这是我想出的两个解决方案:

解决方案 1:使用#if编译器指令并为每个 .NET 框架版本构建一个 DLL,并使用 NuGet 包发布这些版本并在项目站点下载。

这种方法的缺点是,当开发人员将他们的 Visual Studio 项目从 .NET 4.0 更新到 .NET 4.5 时,他们不会自动获得 .NET 4.5 版本(具有 .NET 4.5 的特定功能)。这违反了最小惊讶原则,并且当开发人员在几个月后尝试使用该功能时,他们会对为什么该功能不起作用感到茫然。

解决方案 2:使用单个 DLL 并即时发出类型,当它们存在于当前应用程序域中时,它们会实现这两个新接口。这允许向用户发送单个 DLL,并允许在开发人员在其项目中切换 .NET 框架版本时使用功能。这将使事情“正常工作”。这是我目前正在前进的方向。

由于我需要返回一个需要实现接口的类型,缺点是必须在运行时使用 Reflection.Emit、ModuleBuilder、TypeBuilder 等创建该类型。这是非常讨厌的shizzle。但除此之外,由于必须在新的(匿名)程序集中创建此类型,我必须将一些内部类型公开(需要继承的类型和需要实现的接口)。将这些内部类型公开会污染项目的 API,并且不允许我对这些类型进行更改。

我相信这些是我的选择,但我可能会遗漏一些明显的东西。所以我的问题是,我错过了一种可能性吗?有没有办法绕过解决方案 1 的问题,还是使用运行时类型发射的核心根会更好?

4

2 回答 2

2

您是否考虑过另一个包含缺失项目的自定义组件?然后测试是否存在类型/方法(仅存在于 .net 4.5 中),如果存在,则加载程序集。

这样你就可以保持完全相同的方法和类,并且省去你做所有这些疯狂的发射的痛苦(​​更不用说如果你发现自己做了那么多,你会受到的性能打击)。

于 2013-08-01T14:55:04.783 回答
1

我有一个名为Dynamitey的项目,它允许您在运行时加载一个类型,并使用 DLR 调用它的静态方法和构造函数。与大量反射或发射代码来加载不一定可用的 api 相比,这要少得多。

dynamic bigIntType = new DynamicObjects.LateType("System.Numerics.BigInteger, System.Numerics, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

if (bigIntType.IsAvailable)
{

  var one = bigIntType.@new(1);
  var two = bigIntType.@new(2);

  Assert.IsFalse(one.IsEven);
  Assert.AreEqual(true, two.IsEven);

  var tParsed = bigIntType.Parse("4");

  Assert.AreEqual(true, tParsed.IsEven);
}

我还有一个名为ImpromptuInterface的项目,它将为鸭子可调用匹配它的对象周围的接口发出代理类型(也使用 DLR)。

var targetType =Type.GetType("System.Collections.Generic.IReadOnlyList`1[[System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");

var list = new List<string>{"lala", "la","lala"};
object readonlyList;
if(targetType != null){
    readonlyList = Impromptu.DynamicActLike(list, targetType);
}
于 2013-08-01T15:11:15.470 回答