You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在C#中如何声明仅支持两种类型的属性?

实现方案:自定义泛型包装类 + PropertyGrid类型转换器

1. 定义泛型包装类

先写一个泛型类,把目标值和Expression实例统一包装起来,同时通过隐式转换让赋值更直观:

public class ValueOrExpression<T>
{
    public T? Value { get; private set; }
    public Expression? Expression { get; private set; }
    public bool IsExpression => Expression != null;

    // 隐式转换:直接赋值目标类型(比如bool/int)
    public static implicit operator ValueOrExpression<T>(T value)
    {
        return new ValueOrExpression<T> { Value = value };
    }

    // 隐式转换:直接赋值Expression实例
    public static implicit operator ValueOrExpression<T>(Expression expression)
    {
        // 可选:在这里校验Expression的返回类型是否匹配T,避免无效赋值
        return new ValueOrExpression<T> { Expression = expression };
    }

    // 运行时求值方法,获取最终的T类型结果
    public T Evaluate()
    {
        if (IsExpression)
        {
            return (T)Expression.Evaluate(); // 假设你的Expression类有Evaluate()方法返回object
        }
        return Value ?? throw new InvalidOperationException("未设置有效值或表达式");
    }
}

2. 为PropertyGrid写自定义类型转换器

WinForms的PropertyGrid依赖TypeConverter来处理类型的编辑和显示,我们需要为每个ValueOrExpression<T>写对应的转换器,以bool为例:

public class BoolValueOrExpressionConverter : TypeConverter
{
    // 允许从字符串、bool、Expression类型转换
    public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
    {
        return sourceType == typeof(string) || sourceType == typeof(bool) || sourceType == typeof(Expression) 
               || base.CanConvertFrom(context, sourceType);
    }

    // 把输入内容转换成ValueOrExpression<bool>
    public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value)
    {
        if (value is string inputStr)
        {
            if (inputStr.Equals("true", StringComparison.OrdinalIgnoreCase))
                return new ValueOrExpression<bool>(true);
            if (inputStr.Equals("false", StringComparison.OrdinalIgnoreCase))
                return new ValueOrExpression<bool>(false);
            // 约定用户输入的表达式前缀为"Expr:",或者直接把非bool字符串当作表达式
            var exprText = inputStr.StartsWith("Expr:", StringComparison.OrdinalIgnoreCase) 
                ? inputStr.Substring(5) 
                : inputStr;
            return new ValueOrExpression<bool>(new Expression(exprText));
        }
        if (value is bool b)
            return new ValueOrExpression<bool>(b);
        if (value is Expression expr)
            return new ValueOrExpression<bool>(expr);
        return base.ConvertFrom(context, culture, value);
    }

    // 把包装类转换成PropertyGrid显示的字符串
    public override object? ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
    {
        if (destinationType == typeof(string) && value is ValueOrExpression<bool> voe)
        {
            return voe.IsExpression ? $"Expr: {voe.Expression.ExpressionText}" : voe.Value.ToString();
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }

    // 给PropertyGrid提供下拉选项:true/false/Expression
    public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
    {
        return new StandardValuesCollection(new object[] { true, false, "Expression" });
    }

    // 允许用户输入自定义表达式(非下拉选项的值)
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
    {
        return false;
    }
}

同理,你可以为int、double、DateTime等类型编写对应的IntValueOrExpressionConverter、DoubleValueOrExpressionConverter,逻辑类似,只是调整类型判断和标准值。

3. 在实体属性上应用

把原来的object类型属性替换成ValueOrExpression<T>,并标记对应的TypeConverter:

public class AppSettings
{
    [TypeConverter(typeof(BoolValueOrExpressionConverter))]
    public ValueOrExpression<bool> EnableAutoSave { get; set; } = false;

    [TypeConverter(typeof(IntValueOrExpressionConverter))]
    public ValueOrExpression<int> MaxRetryCount { get; set; } = 3;
}

核心优势

  • 强类型约束:编译时就能阻止无关类型赋值,避免原object类型的类型安全问题
  • 适配PropertyGrid交互:通过TypeConverter实现了用户需要的下拉选择(true/false/Expression)+ 自定义表达式输入,不用拆成两个属性破坏体验
  • 用法自然:支持隐式转换,赋值时直接写EnableAutoSave = true;或EnableAutoSave = new Expression("SomeExpression");,和原object属性的用法几乎一致

内容的提问来源于stack exchange,提问作者Mark Roworth

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 19:45:56