本文整理汇总了C#中TypeSymbol.ContainsTypeParameter方法的典型用法代码示例。如果您正苦于以下问题:C# TypeSymbol.ContainsTypeParameter方法的具体用法?C# TypeSymbol.ContainsTypeParameter怎么用?C# TypeSymbol.ContainsTypeParameter使用的例子?那么恭喜您, 这里精选的方法代码示例或许可以为您提供帮助。您也可以进一步了解该方法所在类TypeSymbol
的用法示例。
在下文中一共展示了TypeSymbol.ContainsTypeParameter方法的2个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: ReportAsOperatorConversionDiagnostics
private static bool ReportAsOperatorConversionDiagnostics(
CSharpSyntaxNode node,
DiagnosticBag diagnostics,
Compilation compilation,
TypeSymbol operandType,
TypeSymbol targetType,
ConversionKind conversionKind,
ConstantValue operandConstantValue)
{
// SPEC: In an operation of the form E as T, E must be an expression and T must be a reference type,
// SPEC: a type parameter known to be a reference type, or a nullable type.
// SPEC: Furthermore, at least one of the following must be true, or otherwise a compile-time error occurs:
// SPEC: • An identity (§6.1.1), implicit nullable (§6.1.4), implicit reference (§6.1.6), boxing (§6.1.7),
// SPEC: explicit nullable (§6.2.3), explicit reference (§6.2.4), or unboxing (§6.2.5) conversion exists
// SPEC: from E to T.
// SPEC: • The type of E or T is an open type.
// SPEC: • E is the null literal.
// SPEC VIOLATION: The specification contains an error in the list of legal conversions above.
// SPEC VIOLATION: If we have "class C<T, U> where T : U where U : class" then there is
// SPEC VIOLATION: an implicit conversion from T to U, but it is not an identity, reference or
// SPEC VIOLATION: boxing conversion. It will be one of those at runtime, but at compile time
// SPEC VIOLATION: we do not know which, and therefore cannot classify it as any of those.
// SPEC VIOLATION: See Microsoft.CodeAnalysis.CSharp.UnitTests.SyntaxBinderTests.TestAsOperator_SpecErrorCase() test for an example.
// SPEC VIOLATION: The specification also unintentionally allows the case where requirement 2 above:
// SPEC VIOLATION: "The type of E or T is an open type" is true, but type of E is void type, i.e. T is an open type.
// SPEC VIOLATION: Dev10 compiler correctly generates an error for this case and we will maintain compatibility.
bool hasErrors = false;
switch (conversionKind)
{
case ConversionKind.ImplicitReference:
case ConversionKind.Boxing:
case ConversionKind.ImplicitNullable:
case ConversionKind.Identity:
case ConversionKind.ExplicitNullable:
case ConversionKind.ExplicitReference:
case ConversionKind.Unboxing:
break;
default:
// Generate an error if there is no possible legal conversion and both the operandType
// and the targetType are closed types OR operandType is void type, otherwise we need a runtime check
if (!operandType.ContainsTypeParameter() && !targetType.ContainsTypeParameter() ||
operandType.SpecialType == SpecialType.System_Void)
{
SymbolDistinguisher distinguisher = new SymbolDistinguisher(compilation, operandType, targetType);
Error(diagnostics, ErrorCode.ERR_NoExplicitBuiltinConv, node, distinguisher.First, distinguisher.Second);
hasErrors = true;
}
break;
}
if (!hasErrors)
{
ReportAsOperatorConstantWarnings(node, diagnostics, operandType, targetType, conversionKind, operandConstantValue);
}
return hasErrors;
}
示例2: GetIsOperatorConstantResult
internal static ConstantValue GetIsOperatorConstantResult(TypeSymbol operandType, TypeSymbol targetType, ConversionKind conversionKind, ConstantValue operandConstantValue)
{
Debug.Assert((object)targetType != null);
// SPEC: The result of the operation depends on D and T as follows:
// SPEC: 1) If T is a reference type, the result is true if D and T are the same type, if D is a reference type and
// SPEC: an implicit reference conversion from D to T exists, or if D is a value type and a boxing conversion from D to T exists.
// SPEC: 2) If T is a nullable type, the result is true if D is the underlying type of T.
// SPEC: 3) If T is a non-nullable value type, the result is true if D and T are the same type.
// SPEC: 4) Otherwise, the result is false.
// NOTE: The language specification talks about the runtime evaluation of the is operation.
// NOTE: However, we are interested in computing the compile time constant value for the expression.
// NOTE: Even though BoundIsOperator and BoundAsOperator will always have no ConstantValue
// NOTE: (they are non-constant expressions according to Section 7.19 of the specification),
// NOTE: we want to perform constant analysis of is/as expressions during binding to generate warnings (always true/false/null)
// NOTE: and during rewriting for optimized codegen.
// NOTE:
// NOTE: Because the heuristic presented here is used to change codegen, it must be conservative. It is acceptable
// NOTE: for us to fail to report a warning in cases where humans could logically deduce that the operator will
// NOTE: always return false. It is not acceptable to inaccurately warn that the operator will always return false
// NOTE: if there are cases where it might succeed.
//
// To begin our heuristic: if the operand is literal null then we automatically return that the
// result is false. You might think that we can simply check to see if the conversion is
// ConversionKind.NullConversion, but "null is T" for a type parameter T is actually classified
// as an implicit reference conversion if T is constrained to reference types. Rather
// than deal with all those special cases we can simply bail out here.
if (operandConstantValue == ConstantValue.Null)
{
return ConstantValue.False;
}
Debug.Assert((object)operandType != null);
switch (conversionKind)
{
case ConversionKind.NoConversion:
// Oddly enough, "x is T" can be true even if there is no conversion from x to T!
//
// Scenario 1: Type parameter compared to System.Enum.
//
// bool M1<X>(X x) where X : struct { return x is Enum; }
//
// There is no conversion from X to Enum, not even an explicit conversion. But
// nevertheless, X could be constructed as an enumerated type.
// However, we can sometimes know that the result will be false.
//
// Scenario 2: Constrained type parameter compared to reference type.
//
// bool M2<X>(X x) where X : struct { return x is string; }
//
// We know that X, constrained to struct, will never be string.
//
// Scenario 3: Value type compared to type parameter.
//
// bool M3<T>(int x) { return x is T; }
//
// There is no conversion from int to T, but T could nevertheless be int.
//
// Scenario 4: Constructed type compared to open type
//
// bool M4<T>(C<int> x) { return x is C<T>; }
//
// There is no conversion from C<int> to C<T>, but nevertheless, T might be int.
//
// Scenario 5: Open type compared to constructed type:
//
// bool M5<X>(C<X> x) { return x is C<int>);
//
// Again, X could be int.
//
// We could then go on to get more complicated. For example,
//
// bool M6<X>(C<X> x) where X : struct { return x is C<string>; }
//
// We know that C<X> is never convertible to C<string> no matter what
// X is. Or:
//
// bool M7<T>(Dictionary<int, int> x) { return x is List<T>; }
//
// We know that no matter what T is, the conversion will never succeed.
//
// As noted above, we must be conservative. We follow the lead of the native compiler,
// which uses the following algorithm:
//
// * If neither type is open and there is no conversion then the result is always false:
if (!operandType.ContainsTypeParameter() && !targetType.ContainsTypeParameter())
{
return ConstantValue.False;
}
// * Otherwise, at least one of them is of an open type. If the operand is of value type
// and the target is a class type other than System.Enum, then we are in scenario 2,
// not scenario 1, and can correctly deduce that the result is false.
if (operandType.IsValueType && targetType.IsClassType() && targetType.SpecialType != SpecialType.System_Enum)
//.........这里部分代码省略.........