【问题标题】:How do you deal with object type switching?你如何处理对象类型切换?
【发布时间】:2011-08-20 17:44:07
【问题描述】:

在 C# 中,问题时常会出现。通常我得到一个对象值,然后我必须为它调用“真实”函数。像这样的:

if (type==typeof(byte))
  val = rs.GetByte(col);
else if (type==typeof(int))
  val = rs.GetInt32(col);
...

if (type==typeof(byte))
  Call((byte)val);
else if (type==typeof(int))
  Call((int)val);
...

我可以在这里看到一个文本模式,但我没有想出一个可以一次性解决所有脏活的解决方案。

你如何处理它?你收到对象值,你必须设置它或传递它,但不是作为对象,而是作为具体类型(POD,可空的 POD 和字符串)和。 ..?

编辑

完整的示例(这个是问题的原因):

    protected IRecord ReadRecord()
    {
        if (!ResultSet.Read())
            return null;

        IRecord record = CreateIRecord();

        var type = record.GetType();
        int column = -1;

        foreach (var prop in type.GetProperties())
        {
            ++column;
            object val;

            if (prop.PropertyType == typeof(byte))
                val = ResultSet.GetByte(column);
            else if (prop.PropertyType == typeof(byte?))
                val = ResultSet.GetSqlByte(column).ToNullable();
            else if (prop.PropertyType == typeof(int))
                val = ResultSet.GetInt32(column);
            else if (prop.PropertyType == typeof(int?))
                val = ResultSet.GetSqlInt32(column).ToNullable();
            else if (prop.PropertyType == typeof(double))
                val = ResultSet.GetDouble(column);
            else if (prop.PropertyType == typeof(double?))
                val = ResultSet.GetSqlDouble(column).ToNullable();
            else if (prop.PropertyType == typeof(DateTime))
                val = ResultSet.GetDateTime(column);
            else if (prop.PropertyType == typeof(DateTime?))
                val = ResultSet.GetSqlDateTime(column).ToNullable();
            else if (prop.PropertyType == typeof(string))
                val = ResultSet.GetString(column);
            else
                throw new ArgumentException("Invalid property type {0}".Expand(prop.PropertyType.ToString()));

            prop.SetValue(record, val, null);
        }

        return record;


    }

【问题讨论】:

  • 你需要有更完整的示例代码;事实上,typerscol 是什么尚不清楚,它们之间的关系(或缺乏关系)也不清楚。
  • @Mr E 这并不总是可行的,尤其是在处理简单类型或不同的对象层次结构时

标签: c# object types switch-statement


【解决方案1】:

您可以使用策略模式。只需将每种类型的策略放在哈希表中,然后您就不需要开关。但是,每个策略都需要一个类。如果您有复杂的逻辑,它特别有用。

如果逻辑相当简单,您还可以使用包含委托的 Hashtable。

//pseudo code
handlers.put(typeof(int), delegate(object value) { return something.GetInt32(value); });

//like this
var handler = handlers[type];
handler.Invoke(val);

【讨论】:

  • 你是说字典?我不认为它更紧凑,除非您使用某种调用方法名称生成器并使用反射来获取方法并调用它。我的第一个示例类似于 new MySwitcher(rs,"Get${TypeName}")。
  • 是的,我的意思是字典,以类型为键,可能以操作为值。当然,您必须在初始化方法中填充字典。但它比很多开关更容易阅读和维护。另外,你真的不需要反思。您可以将几乎任何东西包装在方法中或使用匿名委托。这是非常甜蜜的语法糖。
  • @Falcon,谢谢你——问题是,你必须为每个案例填充这个字典。它仍然有点难看(所以我不会自己使用它,但感谢您分享这个想法)。
  • 您的问题没有好的解决方案。当然,您可以使用方法名称的约定并使用反射,就像您之前所说的那样。这样可以生成漂亮、干净的代码,但可能会导致非常讨厌的运行时错误,并且可能会降低性能。 p.s.有时你只需要写几行代码g
  • @Falcon,运行时错误可能是个大问题,同意,但尽管反射速度很快,但可以在构造函数调用中缓存所有方法。所以它会解决一次(慢),然后使用多次(快)。
【解决方案2】:

您可以使用 is 运算符稍微清理一下:

if (MyType is BaseType)...

【讨论】:

  • 感谢您指出这一点,但主要问题仍然存在。
  • 我一辈子都藏在哪里了?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多