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

C#多数据类型处理类实现方案技术咨询

C# Typed Parameter Class Implementation: Fixes & Better Approaches

Great question! Let’s break down the issues with your current code and walk through more idiomatic, type-safe C# solutions.

Problems with Your Current Implementation

Your approach uses new to shadow the base class’s value field, which creates several pitfalls:

  • Broken polymorphism: If you have a Param reference pointing to a Param_Int instance, accessing value will return the base class’s object field instead of the derived int value. Example:
    Param myParam = new Param_Int("Age");
    Console.WriteLine(myParam.value); // Returns the base object, not the int 1
    
  • No type safety: Retrieving values requires unsafe casting, which can throw runtime exceptions if done incorrectly.
  • Public fields: Exposing public fields violates encapsulation best practices—properties are preferred for control over access and validation.

This approach gives you full type safety while maintaining polymorphism for collections of parameters.

// Optional non-generic base to group all parameter types
public abstract class ParamBase
{
    public string Name { get; }
    protected ParamBase(string name) => Name = name;
    
    // Optional: Get untyped value if needed for serialization/debugging
    public abstract object GetValue();
}

// Generic abstract class for typed parameters
public abstract class Param<T> : ParamBase
{
    public T Value { get; set; }
    
    protected Param(string name, T initialValue) : base(name)
    {
        Value = initialValue;
    }

    public override object GetValue() => Value;
}

// Concrete parameter types
public class IntParam : Param<int>
{
    public IntParam(string name) : base(name, 1) { }
}

public class DoubleParam : Param<double>
{
    public DoubleParam(string name) : base(name, 1.0) { }
}

public class StringParam : Param<string>
{
    public StringParam(string name) : base(name, string.Empty) { }
}

Benefits:

  • Type safety: No casting required when accessing Value—you know exactly what type each parameter holds.
  • Polymorphism: Use ParamBase to store all parameter types in a single collection, while still being able to retrieve typed values via pattern matching:
    var paramsList = new List<ParamBase>
    {
        new IntParam("Age"),
        new DoubleParam("Height"),
        new StringParam("Name")
    };
    
    foreach (var param in paramsList)
    {
        switch (param)
        {
            case IntParam intParam:
                Console.WriteLine($"Int: {intParam.Name} = {intParam.Value}");
                break;
            case DoubleParam doubleParam:
                Console.WriteLine($"Double: {doubleParam.Name} = {doubleParam.Value}");
                break;
        }
    }
    
  • Encapsulation: Properties let you add validation logic later (e.g., restricting IntParam values to positive numbers) without breaking existing code.

Solution 2: Simplified Generic Class (No Derived Types)

If you don’t need type-specific behavior (like custom initial values or validation), you can skip the derived classes entirely:

public class Param<T>
{
    public string Name { get; }
    public T Value { get; set; }

    public Param(string name, T initialValue)
    {
        Name = name;
        Value = initialValue;
    }
}

// Usage
var ageParam = new Param<int>("Age", 1);
var heightParam = new Param<double>("Height", 1.0);
var nameParam = new Param<string>("Name", "");

This is the most concise option for straightforward parameter storage.

What to Avoid

Stick to the generic approaches above instead of shadowing fields with new. If you absolutely need a non-generic base without generics, you could use virtual properties—but this brings back casting risks:

public abstract class Param
{
    public string Name { get; }
    public abstract object Value { get; set; }
    protected Param(string name) => Name = name;
}

public class IntParam : Param
{
    private int _value;
    public override object Value
    {
        get => _value;
        set => _value = (int)value; // Risk of InvalidCastException
    }

    public IntParam(string name) : base(name) => _value = 1;
}

This is not recommended unless you have strict legacy constraints.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:39:26