我能使用.NET 4的功能来定位.NET 3.5 SP1吗?

5

我希望在Visual Studio 2010中使用一些.NET 4.0的功能,但仍然针对.NET 3.5进行目标设置。基本上我想要像这样的东西:

if (.NET 4 installed) then
    execute .NET 4 feature

这是一个可选功能,如果系统安装了.NET 4.0,我希望它能够运行。如果系统只有.NET 3.5,则该功能不会执行,因为它对应用程序并不是必要的。


1
你愿意将这个功能作为一个独立的程序集吗? - Gabe
@nathan - 虽然答案可能最终相同,但我不认为这个问题是那个问题的重复。 - slugster
你应该明确指出你感兴趣的功能。有些功能比其他功能更容易访问。 - Gabe
可能相关,但不是重复:C#条件编译和框架目标 - Cody Gray
如果安装了.NET 4,我想使用TextOptions.TextFormattingMode="Display",否则只需使用普通文本呈现。 - Luke
@slugster,@nathan:问题不仅不同,答案也不同。 - Gabe
4个回答

9

首先,您需要针对3.5版本的框架进行目标定位,但通过使用类似于以下的App.config配置文件,使您的程序能够由4.0框架加载(来自如何强制应用程序使用.NET 3.5或更高版本?):

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0"/>
    <supportedRuntime version="v2.0.50727"/>
  </startup>
</configuration>

关于如何激活4.0功能,取决于您想使用的功能。如果是内置类中的方法,只需查找并使用该方法(如果存在)。以下是C#示例(同样适用于VB):

var textOptions = Type.GetType("System.Windows.Media.TextOptions, " +
        "PresentationFramework, Version=4.0.0.0, " +
        "Culture=neutral, PublicKeyToken=31bf3856ad364e35");
if (textOptions != null)
{
    var setMode = textOptions.GetMethod("SetTextFormattingMode");
    if (setMode != null)
         // don't bother to lookup TextFormattingMode.Display -- we know it's 1
        setMode.Invoke(null, new object[] { this, 1 });
}

如果您将这段代码放在您的MainWindow构造函数中,它将在运行于.NET 4.0框架下的应用程序中设置TextFormattingModeDisplay,而在3.5下则不会有任何效果。
如果您想使用在3.5中不可用的类型,则必须为其创建一个新的程序集。例如,创建一个名为“Factorial”的类库项目,目标为4.0,其中包含以下代码(您需要添加对System.Numerics的引用;同样适用于C#):
using System.Numerics;

namespace Factorial
{
    public class BigFactorial
    {
        public static object Factorial(int arg)
        {
            BigInteger accum = 1;  // BigInteger is in 4.0 only
            while (arg > 0)
                accum *= arg--;
            return accum;
        }
    }
}

然后创建一个目标为3.5的项目,使用以下代码(同样的C#声明):
using System;
using System.Reflection;

namespace runtime
{
    class Program
    {
        static MethodInfo factorial;

        static Program()
        {   // look for Factorial.dll
            try
            {
                factorial = Assembly.LoadFrom("Factorial.dll")
                           .GetType("Factorial.BigFactorial")
                           .GetMethod("Factorial");
            }
            catch
            { // ignore errors; we just won't get this feature
            }
        }

        static object Factorial(int arg)
        {
            // if the feature is needed and available, use it
            if (arg > 20 && factorial != null)
                return factorial.Invoke(null, new object[] { arg });
            // default to regular behavior
            long accum = 1;
            while (arg > 0)
                accum = checked(accum * arg--);
            return accum;
        }

        static void Main(string[] args)
        {
            try
            {
                for (int i = 0; i < 25; i++)
                    Console.WriteLine(i + ": " + Factorial(i));
            }
            catch (OverflowException)
            {
                if (Environment.Version.Major == 4)
                    Console.WriteLine("Factorial function couldn't be found");
                else
                    Console.WriteLine("You're running " + Environment.Version);
            }
        }
    }
}

如果您将EXE和Factorial.DLL复制到同一个目录中并运行它,您将获得所有小于4.0的前25个阶乘,但只有在3.5版本下才能获取前20个阶乘,并且会显示错误消息(或者如果找不到DLL)。


谢谢。如果计算机同时安装了.NET 3.5和4.0,它会使用最新的.NET 4.0还是在.NET 3.5中运行? - Luke
基本上,如果已安装.NET 4.0,则我想使用TextOptions.TextFormattingMode="Display",否则只需使用普通文本呈现。我不需要任何其他.NET 4.0功能。 - Luke
@Luke:如果你在项目中将目标设置为.NET 3.5并在App.config中添加,那么如果可用的话,你将运行v4.0,否则是v3.5。请参考我的更新示例,了解如何设置“TextFormattingMode”。 - Gabe

3

不可以。一个有限的选项是使用条件编译,像这样:

#if NET40
    some 4.0 code 
#else
    some 3.5 code
#endif

但是这种方法的限制在于它要么编译代码,要么不编译-你不能在运行时切换执行路径。(条件编译符号 可以在文件顶部、项目属性构建选项卡中声明,或在编译项目时在命令行上声明(因此可以作为自动化构建的一部分指定))。
最好的做法是确保安装了 .Net 4.0 框架 - 它只有 49MB 的完整版本,所以并不会很大。

我同意有先决条件的设定,但是你的 #ifdef 语句使用了一个常量,而没有说明该常量在哪里定义或如何定义。即使提供一下我提到的可能重复的问题的链接也会很有帮助。 - nathan gonzalez
@nathan - 我已经扩展了我的答案,我假设大多数人都知道如何声明条件编译符号。 - slugster
谢谢。我假设有人问一个4.0的特性能否在3.5的应用程序中编译,可能不知道MSBuild的更深层次。 - nathan gonzalez

1

主要问题是,你不能在.NET 4 CLR或其相反版本上运行为.NET 3.5编译的代码。你需要重新为.NET 4编译。

所以你将有两个可执行文件,一个是.NET 3.5的,另一个是.NET 4的。两者都有相同的代码,但你可以使用预处理器指令,具体来说是#IF指令,在这两者之间进行区别。

然后在两个项目的配置中指定特定的指令。


0
不行,因为没有.NET 4 CLR,你无法使用.NET 4功能。问题在于程序集在加载时绑定,而程序集绑定到你编译的CLR的特定版本。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接