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 [System.Security.SecuritySafeCritical]
29 private static void ParseTargetFrameworkName(out string identifier, out string profile, out int version)
31 string targetFrameworkMoniker = AppDomain.CurrentDomain.SetupInformation.TargetFrameworkName;
33 // If we don't have a TFM then we should default to the 4.0 behavior where all quirks are turned on.
34 if (!TryParseFrameworkName(targetFrameworkMoniker, out identifier, out version, out profile))
37 if (CompatibilitySwitches.UseLatestBehaviorWhenTFMNotSpecified)
39 // If we want to use the latest behavior it is enough to set the value of the switch to string.Empty.
40 // When the get to the caller of this method (PopulateDefaultValuesPartial) we are going to use the
41 // identifier we just set to decide which switches to turn on. By having an empty string as the
42 // identifier we are simply saying -- don't turn on any switches, and we are going to get the latest
43 // behavior for all the switches
44 identifier = string.Empty;
49 identifier = ".NETFramework";
51 profile = string.Empty;
56 // This code was a constructor copied from the FrameworkName class, which is located in System.dll.
57 // Parses strings in the following format: "<identifier>, Version=[v|V]<version>, Profile=<profile>"
58 // - The identifier and version is required, profile is optional
59 // - Only three components are allowed.
60 // - The version string must be in the System.Version format; an optional "v" or "V" prefix is allowed
61 private static bool TryParseFrameworkName(String frameworkName, out String identifier, out int version, out String profile)
63 // For parsing a target Framework moniker, from the FrameworkName class
64 const char c_componentSeparator = ',';
65 const char c_keyValueSeparator = '=';
66 const char c_versionValuePrefix = 'v';
67 const String c_versionKey = "Version";
68 const String c_profileKey = "Profile";
70 identifier = profile = string.Empty;
73 if (frameworkName == null || frameworkName.Length == 0)
78 String[] components = frameworkName.Split(c_componentSeparator);
81 // Identifer and Version are required, Profile is optional.
82 if (components.Length < 2 || components.Length > 3)
88 // 1) Parse the "Identifier", which must come first. Trim any whitespace
90 identifier = components[0].Trim();
92 if (identifier.Length == 0)
97 bool versionFound = false;
101 // The required "Version" and optional "Profile" component can be in any order
103 for (int i = 1; i < components.Length; i++)
105 // Get the key/value pair separated by '='
106 string[] keyValuePair = components[i].Split(c_keyValueSeparator);
108 if (keyValuePair.Length != 2)
113 // Get the key and value, trimming any whitespace
114 string key = keyValuePair[0].Trim();
115 string value = keyValuePair[1].Trim();
118 // 2) Parse the required "Version" key value
120 if (key.Equals(c_versionKey, StringComparison.OrdinalIgnoreCase))
124 // Allow the version to include a 'v' or 'V' prefix...
125 if (value.Length > 0 && (value[0] == c_versionValuePrefix || value[0] == 'V'))
127 value = value.Substring(1);
129 Version realVersion = new Version(value);
130 // The version class will represent some unset values as -1 internally (instead of 0).
131 version = realVersion.Major * 10000;
132 if (realVersion.Minor > 0)
133 version += realVersion.Minor * 100;
134 if (realVersion.Build > 0)
135 version += realVersion.Build;
138 // 3) Parse the optional "Profile" key value
140 else if (key.Equals(c_profileKey, StringComparison.OrdinalIgnoreCase))
142 if (!String.IsNullOrEmpty(value))
161 // This is a partial method. Platforms (such as Desktop) can provide an implementation of it that will read override value
162 // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls
163 // to it from the code
164 static partial void TryGetSwitchOverridePartial(string switchName, ref bool overrideFound, ref bool overrideValue);
166 /// This is a partial method. This method is responsible for populating the default values based on a TFM.
167 /// It is partial because each library should define this method in their code to contain their defaults.
168 static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version);