278 lines
11 KiB
C#
278 lines
11 KiB
C#
|
//------------------------------------------------------------------------------
|
||
|
// <copyright file="NullableConverter.cs" company="Microsoft">
|
||
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
// </copyright>
|
||
|
//------------------------------------------------------------------------------
|
||
|
|
||
|
namespace System.ComponentModel {
|
||
|
using System.Collections;
|
||
|
using System.ComponentModel.Design.Serialization;
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.Reflection;
|
||
|
using System.Runtime.InteropServices;
|
||
|
using System.Runtime.Remoting;
|
||
|
using System.Runtime.Serialization.Formatters;
|
||
|
using System.Security.Permissions;
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
[HostProtection(SharedState = true)]
|
||
|
public class NullableConverter : TypeConverter {
|
||
|
Type nullableType;
|
||
|
Type simpleType;
|
||
|
TypeConverter simpleTypeConverter;
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.NullableConverter"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public NullableConverter(Type type)
|
||
|
{
|
||
|
this.nullableType = type;
|
||
|
|
||
|
this.simpleType = Nullable.GetUnderlyingType(type);
|
||
|
if (this.simpleType == null) {
|
||
|
throw new ArgumentException(SR.GetString(SR.NullableConverterBadCtorArg), "type");
|
||
|
}
|
||
|
|
||
|
this.simpleTypeConverter = TypeDescriptor.GetConverter(this.simpleType);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.CanConvertFrom"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType) {
|
||
|
if (sourceType == this.simpleType) {
|
||
|
return true;
|
||
|
}
|
||
|
else if (this.simpleTypeConverter != null) {
|
||
|
return this.simpleTypeConverter.CanConvertFrom(context, sourceType);
|
||
|
}
|
||
|
else {
|
||
|
return base.CanConvertFrom(context, sourceType);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.ConvertFrom"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
|
||
|
if (value == null || value.GetType() == this.simpleType) {
|
||
|
return value;
|
||
|
}
|
||
|
else if (value is String && String.IsNullOrEmpty(value as String)) {
|
||
|
return null;
|
||
|
}
|
||
|
else if (this.simpleTypeConverter != null) {
|
||
|
object convertedValue = this.simpleTypeConverter.ConvertFrom(context, culture, value);
|
||
|
return convertedValue;
|
||
|
}
|
||
|
else {
|
||
|
return base.ConvertFrom(context, culture, value);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.CanConvertTo"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) {
|
||
|
if (destinationType == this.simpleType) {
|
||
|
return true;
|
||
|
}
|
||
|
else if (destinationType == typeof(InstanceDescriptor)) {
|
||
|
return true;
|
||
|
}
|
||
|
else if (this.simpleTypeConverter != null) {
|
||
|
return this.simpleTypeConverter.CanConvertTo(context, destinationType);
|
||
|
}
|
||
|
else {
|
||
|
return base.CanConvertTo(context, destinationType);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.ConvertTo"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType) {
|
||
|
if (destinationType == null) {
|
||
|
throw new ArgumentNullException("destinationType");
|
||
|
}
|
||
|
|
||
|
if (destinationType == this.simpleType && this.nullableType.IsInstanceOfType(value)) {
|
||
|
return value;
|
||
|
}
|
||
|
else if (destinationType == typeof(InstanceDescriptor)) {
|
||
|
ConstructorInfo ci = nullableType.GetConstructor(new Type[] {simpleType});
|
||
|
Debug.Assert(ci != null, "Couldn't find constructor");
|
||
|
return new InstanceDescriptor(ci, new object[] {value}, true);
|
||
|
}
|
||
|
else if (value == null) {
|
||
|
// Handle our own nulls here
|
||
|
if (destinationType == typeof(string)) {
|
||
|
return string.Empty;
|
||
|
}
|
||
|
}
|
||
|
else if (this.simpleTypeConverter != null) {
|
||
|
return this.simpleTypeConverter.ConvertTo(context, culture, value, destinationType);
|
||
|
}
|
||
|
|
||
|
return base.ConvertTo(context, culture, value, destinationType);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.CreateInstance"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
object instance = simpleTypeConverter.CreateInstance(context, propertyValues);
|
||
|
return instance;
|
||
|
}
|
||
|
|
||
|
return base.CreateInstance(context, propertyValues);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a value indicating whether changing a value on this object requires a
|
||
|
/// call to <see cref='System.ComponentModel.TypeConverter.CreateInstance'/> to create a new value,
|
||
|
/// using the specified context.</para>
|
||
|
/// </devdoc>
|
||
|
public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
return simpleTypeConverter.GetCreateInstanceSupported(context);
|
||
|
}
|
||
|
|
||
|
return base.GetCreateInstanceSupported(context);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a collection of properties for
|
||
|
/// the type of array specified by the value parameter using the specified context and
|
||
|
/// attributes.</para>
|
||
|
/// </devdoc>
|
||
|
public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
object unwrappedValue = value;
|
||
|
return simpleTypeConverter.GetProperties(context, unwrappedValue, attributes);
|
||
|
}
|
||
|
|
||
|
return base.GetProperties(context, value, attributes);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a value indicating
|
||
|
/// whether this object supports properties using the
|
||
|
/// specified context.</para>
|
||
|
/// </devdoc>
|
||
|
public override bool GetPropertiesSupported(ITypeDescriptorContext context) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
return simpleTypeConverter.GetPropertiesSupported(context);
|
||
|
}
|
||
|
|
||
|
return base.GetPropertiesSupported(context);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a collection of standard values for the data type this type converter is
|
||
|
/// designed for.</para>
|
||
|
/// </devdoc>
|
||
|
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
StandardValuesCollection values = simpleTypeConverter.GetStandardValues(context);
|
||
|
if (GetStandardValuesSupported(context) && values != null) {
|
||
|
// Create a set of standard values around nullable instances.
|
||
|
object[] wrappedValues = new object[values.Count + 1];
|
||
|
int idx = 0;
|
||
|
|
||
|
wrappedValues[idx++] = null;
|
||
|
foreach(object value in values) {
|
||
|
wrappedValues[idx++] = value;
|
||
|
}
|
||
|
|
||
|
return new StandardValuesCollection(wrappedValues);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return base.GetStandardValues(context);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a value indicating whether the collection of standard values returned from
|
||
|
/// <see cref='System.ComponentModel.TypeConverter.GetStandardValues'/> is an exclusive
|
||
|
/// list of possible values, using the specified context.</para>
|
||
|
/// </devdoc>
|
||
|
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
return simpleTypeConverter.GetStandardValuesExclusive(context);
|
||
|
}
|
||
|
|
||
|
return base.GetStandardValuesExclusive(context);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets a value indicating
|
||
|
/// whether this object
|
||
|
/// supports a standard set of values that can be picked
|
||
|
/// from a list using the specified context.</para>
|
||
|
/// </devdoc>
|
||
|
public override bool GetStandardValuesSupported(ITypeDescriptorContext context) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
return simpleTypeConverter.GetStandardValuesSupported(context);
|
||
|
}
|
||
|
|
||
|
return base.GetStandardValuesSupported(context);
|
||
|
}
|
||
|
|
||
|
/// <devdoc>
|
||
|
/// <para>Gets
|
||
|
/// a value indicating whether the given value object is valid for this type.</para>
|
||
|
/// </devdoc>
|
||
|
public override bool IsValid(ITypeDescriptorContext context, object value) {
|
||
|
if (simpleTypeConverter != null) {
|
||
|
object unwrappedValue = value;
|
||
|
if (unwrappedValue == null) {
|
||
|
return true; // null is valid for nullable.
|
||
|
}
|
||
|
else {
|
||
|
return simpleTypeConverter.IsValid(context, unwrappedValue);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return base.IsValid(context, value);
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.NullableType"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public Type NullableType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return nullableType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.UnderlyingType"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public Type UnderlyingType
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return simpleType;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <include file='doc\NullableConverter.uex' path='docs/doc[@for="NullableConverter.UnderlyingTypeConverter"]/*' />
|
||
|
/// <devdoc>
|
||
|
/// </devdoc>
|
||
|
public TypeConverter UnderlyingTypeConverter
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
return simpleTypeConverter;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|