Получить версию целевой платформы и профиль целевой платформы из сборки .Net

Есть ли способ получить доступ к значениям, которые использовались для TargetFrameworkVersion и / или TargetFrameworkProfile при компиляции сборки .Net?

Я говорю о тех значениях, которые содержатся в файле проекта.

<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <PropertyGroup>
    <OtherStuff />
    <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
    <TargetFrameworkProfile>Client</TargetFrameworkProfile>
    <OtherStuff />
  </PropertyGroup>
  <OtherStuff>
  </OtherStuff>
</Project>

По сути, я хотел бы узнать, какой была целевая версия платформы при компиляции сборки, а также, если возможно, целевой профиль платформы.

И я не говорю о загруженной в данный момент версии CLR, Environment.Version - это не то, что мне нужно.

В идеале решение должно использовать System.Reflection, но если мне придется прибегнуть к другим методам, я это сделаю.


person Scott    schedule 28.07.2011    source источник
comment
Я считаю, что TargetFrameworkProfile влияет только на то, какие ссылки Visual Studio позволит вам делать из проекта. Я не думаю, что что-то компилируется в выходную сборку.   -  person Damien_The_Unbeliever    schedule 28.07.2011
comment
Дэмиен, я думаю, ты прав. Я не вижу его в списке доступного свойства уровня проекта, которое можно передать в MSBuild. Если он не собирается в MSBuild, он определенно не будет встроен в сборку. Я все еще могу жить в надежде, что TargetFrameworkVersion где-то там встроена.   -  person Scott    schedule 28.07.2011
comment
public string TargetFrameworkProfile { get; set; } Microsoft.Build.Tasks   -  person Mark Schultheiss    schedule 23.05.2018


Ответы (5)


Если вас устраивает версия CLR, которая скомпилировала сборку, вы можете использовать _ 1_. Согласно MSDN, это свойство:

представляющая версию среды CLR, сохраненную в файле, содержащем манифест.

а также

По умолчанию для ImageRuntimeVersion задана версия CLR, используемая для построения сборки. Однако во время компиляции могло быть установлено другое значение.

Конечно, это не дает вам конкретной версии .NET Framework (например: .NET Framework 2, 3.0 и 3.5 все находятся в 2.0 CLR).

Если версии CLR недостаточно, вы можете попытаться «оценить» (разумно угадать), какая версия должна быть основана на сборках, на которые она ссылается. Для .NET 1 и 4 версии CLR должно быть достаточно. Однако, если бы версия CLR была 2.0, вы бы не знали, означает ли это 2.0, 3.0 или 3.5, поэтому вы могли бы попробовать еще немного логики. Например, если вы видели, что сборка ссылается на System.Core (используя Assembly.GetReferencedAssemblies() ), то вы должны знать, что это версия 3.5, поскольку System.Core был новым в 3.5. Это не совсем надежно, поскольку рассматриваемая сборка может не использовать какие-либо типы из сборки, поэтому вы не сможете это уловить. Чтобы попытаться поймать больше случаев, вы можете перебрать все сборки, на которые есть ссылки, и проверить их номера версий - возможно, отфильтровать только сборки, которые начинаются с System, чтобы избежать ложных срабатываний с другими библиотеками. Если вы видите какие-либо упомянутые сборки System. *, Имеющие версию 3.5.x.x, то вы также можете быть уверены, что она была создана для 3.5.


Как вы заметили, я не верю, что TargetFrameworkProfile ускользнет от Visual Studio. Однако, если для приложения есть файл app.config, Visual Studio могла поместить туда целевую платформу. Например, если вы настроили проект на использование клиентского профиля 4.0, Visual Studio создаст app.config следующим образом:

<?xml version="1.0"?>
<configuration>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client"/>
  </startup>
</configuration>
person Stephen McDaniel    schedule 13.09.2011
comment
У меня есть R1.dll с Target Framework 4.5 и R2.dll с Target Framework 4.0. CLR 4.0 для dll. затем у меня есть P1.dll, скомпилированный с Target Framework 4.0. Может ли P1.dll ссылаться на R1.dll во время выполнения? - person Kiquenet; 28.03.2014
comment
@Kiquenet Это кажется несколько несвязанным вопросом. Возможно, вы захотите проверить другие вопросы, которые более тесно связаны с вашим вопросом. Например: Можно ли сослаться на сборку, предназначенную для .net 4.5, в проекте, ориентированном на 4.0? или Обновление до .Net 4.5 приводит к сбою сборки? - person Stephen McDaniel; 28.03.2014
comment
Спасибо, Стивен МакДэниел - я надеялся, что кто-то даст лучший ответ, но я не думаю, что это произойдет. Кажется, что правильный ответ - нет, но я приму ваш ответ, так как он все равно содержит некоторую полезную информацию. - person Scott; 22.04.2014
comment
Очень интересный ответ. Я с удивлением обнаружил, что поддерживаемая среда выполнения .NET настолько неясна, чтобы ее можно было найти в сборке, но все же хорошо работает с интеллектуальным подходом к предположениям. У вас есть идеи или ссылки, чтобы указать мне, как Mono справляется с этим? Я знаю, что версия mono не имеет отношения к поддерживаемой среде выполнения .NET, которую может поддерживать моно-скомпилированная сборка. Тем не менее, мне интересно, будет ли ваш трюк работать таким же образом для сборок, скомпилированных с помощью моно? - person Ivaylo Slavov; 28.04.2015
comment
@IvayloSlavov Я ожидал, что моя логика предположений будет работать даже в контексте моно. Я взглянул на случайный класс, который, как мне известно, существует только в .net 3.5 (System.Linq.Enumerable), и его моноверсия также объявлена ​​в файле System.Core.dll. Я ожидал, что большинство типов будут такими же. Но, вероятно, лучший способ узнать наверняка - это проверить и увидеть. :-) - person Stephen McDaniel; 28.04.2015

Если сборка была скомпилирована с помощью TargetFrameworkAttribute (в области сборки) вы можете легко и единообразно определить целевой профиль платформы.

Попробуйте этот пример и укажите в своих собственных сборках разные цели.

class Program
{
    static void Main(string[] args)
    {


        // Lets examine all assemblies loaded into the current application domain.
        var assems = AppDomain.CurrentDomain.GetAssemblies();

        // The target framework attribute used when the assemby was compiled.
        var filteredType = typeof(TargetFrameworkAttribute);

        // Get all assemblies that have the TargetFrameworkAttribute applied.
        var assemblyMatches = assems.Select(x => new { Assembly = x, TargetAttribute = (TargetFrameworkAttribute)x.GetCustomAttribute(filteredType) })
                                    .Where(x => x.TargetAttribute != null);

        // Report assemblies framework target
        foreach (var assem in assemblyMatches)
        {
            var framework = new System.Runtime.Versioning.FrameworkName(assem.TargetAttribute.FrameworkName);
            Console.WriteLine("Assembly: '{0}' targets .NET version: '{1}'.",
                                assem.Assembly.FullName,
                                framework.Version);
        }

        Console.ReadLine();
    }
}
person njappboy    schedule 30.05.2014

Это должно сработать!

- ›Скомпилируйте bin \ net45 \ myapp.exe = .NET Framework 4.5

var asm = Assembly.GetExecutingAssembly();
var b = asm.CustomAttributes.FirstOrDefault(a => a.AttributeType == typeof(TargetFrameworkAttribute));
var strFramework = b.NamedArguments[0].TypedValue.Value;

Console.WriteLine(strFramework);
person Latency    schedule 29.07.2020
comment
Для сборок .NET 5 я мог бы получить значимую целевую версию, используя b?.ConstructorArguments[0].Value вместо b.NamedArguments[0].TypedValue.Value. - person Alexei - check Codidact; 11.07.2021

Попробуйте также этот пример, чтобы получить как целевую, так и текущую версии .NET framework во время выполнения (работает для .NET V4.X):

    Dim ca As Object() = System.Reflection.Assembly.GetEntryAssembly().GetCustomAttributes(False)

    For Each c In ca.Where(Function(x) x.TypeId.Name = "TargetFrameworkAttribute")
        Console.WriteLine("Target .NET framework for " & Application.ProductName & " : " & c.FrameworkDisplayName)
    Next

    Console.WriteLine("Current .NET framework for " & Application.ProductName & " : " & System.Diagnostics.FileVersionInfo.GetVersionInfo(GetType(Integer).Assembly.Location).ProductVersion)
person Didier L    schedule 19.07.2016

Решение njappboy отлично работает. Мне нужна была версия VB.Net, так что вот конвертация.

Dim assems = AppDomain.CurrentDomain.GetAssemblies()
Dim filteredType = GetType(Runtime.Versioning.TargetFrameworkAttribute)
Dim assemblyMatches = assems.[Select](Function(x) New With {Key .Assembly = x,
            Key .TargetAttribute = CType(x.GetCustomAttribute(filteredType),
            Runtime.Versioning.TargetFrameworkAttribute)}).Where(
            Function(x) x.TargetAttribute IsNot Nothing)
For Each assem In assemblyMatches
    Dim framework = New System.Runtime.Versioning.FrameworkName(
        assem.TargetAttribute.FrameworkName)

    Console.WriteLine("Assembly: '{0}' targets .NET version: '{1}'.",
                      assem.Assembly.FullName, framework.Version)
Next
person Gregory Bologna    schedule 10.05.2018