private void DefineParameter(MethodBuilder methodBuilder, ConstructorBuilder constructorBuilder, Cci.IParameterDefinition paramDef) { // No explicit param row is needed if param has no flags (other than optionally IN), // no name and no references to the param row, such as CustomAttribute, Constant, or FieldMarshall var attributes = paramDef.GetAttributes(_context); var defaultValue = paramDef.GetDefaultValue(_context); if (defaultValue != null || paramDef.IsOptional || paramDef.IsOut || paramDef.IsMarshalledExplicitly || attributes.Any() || paramDef.Name.Length > 0) { int index = paramDef is Cci.ReturnValueParameter ? 0 : paramDef.Index + 1; ParameterAttributes attrs = (ParameterAttributes)Cci.MetadataWriter.GetParameterFlags(paramDef); ParameterBuilder paramBuilder = (methodBuilder != null) ? methodBuilder.DefineParameter(index, attrs, paramDef.Name) : constructorBuilder.DefineParameter(index, attrs, paramDef.Name); if (defaultValue != null) { object rawValue = defaultValue.Value; if (rawValue == null) { var paramTypeRef = paramDef.GetType(_context); if (paramTypeRef.IsValueType) { SetParameterDefaultStructValue(paramBuilder); } else { paramBuilder.SetConstant(null); } } else { // TODO (tomat): Ref.Emit has too strict checks on the constant type. While it is ok to emit value, // e.g. of type Int16 for parameter of type Int32 to metadata, Ref.Emit checks if these types are Type.IsAssignableFrom. // To make this work we need to convert. // // We also need to support Nullable<T>. if (rawValue.GetType().IsPrimitive) { // parameter type has already been resolved once when defining the method, so just retrive it: Type paramType = ResolveType(paramDef.GetType(_context)); if (paramType.IsGenericType && paramType.GetGenericTypeDefinition() == typeof(Nullable<>)) { paramType = paramType.GetGenericArguments()[0]; } if (paramType.IsEnum) { // If emitting the enum, it isn't "created" as this stage so Enum.GetUnderlyingType() will throw // Otherwise, if the enum is already defined, we should use Enum.GetUnderlyingType() to get the correct type paramType = paramType is TypeBuilder ? paramType.UnderlyingSystemType : Enum.GetUnderlyingType(paramType); } rawValue = Convert.ChangeType(rawValue, paramType, System.Globalization.CultureInfo.InvariantCulture); } paramBuilder.SetConstant(rawValue); } } if (paramDef.IsMarshalledExplicitly) { // FieldMarshal var marshallingInformation = paramDef.MarshallingInformation; if (marshallingInformation != null) { paramBuilder.SetCustomAttribute(GetMarshalAsAttribute(marshallingInformation)); } else { Debug.Assert(!paramDef.MarshallingDescriptor.IsDefaultOrEmpty); // TODO: throw new NotImplementedException(); } } EmitCustomAttributes(paramBuilder, attributes); } }