3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 using System.Collections.Generic;
11 internal static partial class AppContextDefaultValues
13 public static void PopulateDefaultValues()
15 string platformIdentifier, profile;
18 ParseTargetFrameworkName(out platformIdentifier, out profile, out version);
20 // Call into each library to populate their default switches
21 PopulateDefaultValuesPartial(platformIdentifier, profile, version);
25 /// We have this separate method for getting the parsed elements out of the TargetFrameworkName so we can
26 /// more easily support this on other platforms.
28 private static void ParseTargetFrameworkName(out string identifier, out string profile, out int version)
30 string targetFrameworkMoniker = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
32 // If we don't have a TFM then we should default to the 4.0 behavior where all quirks are turned on.
33 if (!TryParseFrameworkName(targetFrameworkMoniker, out identifier, out version, out profile))
36 if (CompatibilitySwitches.UseLatestBehaviorWhenTFMNotSpecified)
38 // If we want to use the latest behavior it is enough to set the value of the switch to string.Empty.
39 // When the get to the caller of this method (PopulateDefaultValuesPartial) we are going to use the
40 // identifier we just set to decide which switches to turn on. By having an empty string as the
41 // identifier we are simply saying -- don't turn on any switches, and we are going to get the latest
42 // behavior for all the switches
43 identifier = string.Empty;
48 identifier = ".NETFramework";
50 profile = string.Empty;
55 // This code was a constructor copied from the FrameworkName class, which is located in System.dll.
56 // Parses strings in the following format: "<identifier>, Version=[v|V]<version>, Profile=<profile>"
57 // - The identifier and version is required, profile is optional
58 // - Only three components are allowed.
59 // - The version string must be in the System.Version format; an optional "v" or "V" prefix is allowed
60 private static bool TryParseFrameworkName(String frameworkName, out String identifier, out int version, out String profile)
62 // For parsing a target Framework moniker, from the FrameworkName class
63 const char c_componentSeparator = ',';
64 const char c_keyValueSeparator = '=';
65 const char c_versionValuePrefix = 'v';
66 const String c_versionKey = "Version";
67 const String c_profileKey = "Profile";
69 identifier = profile = string.Empty;
72 if (frameworkName == null || frameworkName.Length == 0)
77 String[] components = frameworkName.Split(c_componentSeparator);
80 // Identifer and Version are required, Profile is optional.
81 if (components.Length < 2 || components.Length > 3)
87 // 1) Parse the "Identifier", which must come first. Trim any whitespace
89 identifier = components[0].Trim();
91 if (identifier.Length == 0)
96 bool versionFound = false;
100 // The required "Version" and optional "Profile" component can be in any order
102 for (int i = 1; i < components.Length; i++)
104 // Get the key/value pair separated by '='
105 string[] keyValuePair = components[i].Split(c_keyValueSeparator);
107 if (keyValuePair.Length != 2)
112 // Get the key and value, trimming any whitespace
113 string key = keyValuePair[0].Trim();
114 string value = keyValuePair[1].Trim();
117 // 2) Parse the required "Version" key value
119 if (key.Equals(c_versionKey, StringComparison.OrdinalIgnoreCase))
123 // Allow the version to include a 'v' or 'V' prefix...
124 if (value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V'))
126 value = value.Substring(1);
128 Version realVersion = new Version(value);
129 // The version class will represent some unset values as -1 internally (instead of 0).
130 version = realVersion.Major * 10000;
131 if (realVersion.Minor > 0)
132 version += realVersion.Minor * 100;
133 if (realVersion.Build > 0)
134 version += realVersion.Build;
137 // 3) Parse the optional "Profile" key value
139 else if (key.Equals(c_profileKey, StringComparison.OrdinalIgnoreCase))
141 if (!String.IsNullOrEmpty(value))
160 // This is a partial method. Platforms (such as Desktop) can provide an implementation of it that will read override value
161 // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
162 // to it from the code
163 static partial void TryGetSwitchOverridePartial(string switchName, ref bool overrideFound, ref bool overrideValue);
165 /// This is a partial method. This method is responsible for populating the default values based on a TFM.
166 /// It is partial because each library should define this method in their code to contain their defaults.
167 static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);