【问题标题】:Variable Return Type of a Method in C#C#中方法的变量返回类型
【发布时间】:2012-05-17 00:09:02
【问题描述】:

我想给一个方法一个参数,我希望我的方法通过查看参数来返回数据。数据可以是布尔、字符串、整数等类型。如何从方法中返回变量类型?我不想返回一个对象类型,然后将其转换为另一种类型。例如:

BlaBla VariableReturnExampleMethod(int a)
{
    if (a == 1)
        return "Demo";
    else if (a == 2)
        return 2;
    else if (a == 3)
        return True;
    else
        return null;
}

我想要这样做的原因是我有一种方法可以从数据库中读取一行的选定列。列的类型不一样,但我必须返回每一列的信息。

【问题讨论】:

标签: c# multiple-variable-return


【解决方案1】:

如何从方法中返回变量类型?我不想返回一个对象类型,然后将其转换为另一种类型。

这基本上就是你必须做的。或者,如果您使用 C# 4,则可以将返回类型设为 dynamic,这将允许隐式转换:

dynamic VariableReturnExampleMethod(int a)
{
    // Body as per question
}

...

// Fine...
int x = VariableReturnExampleMethod(2);

// This will throw an exception at execution time
int y = VariableReturnExampleMethod(1);

从根本上说,您指定类型以让编译器 知道会发生什么。如果类型只在 执行 时知道,那怎么能工作呢? dynamic 版本起作用的原因是它基本上告诉编译器将其正常工作推迟到直到执行时间 - 所以你失去了正常的安全性,这会让第二个示例在编译时失败。

【讨论】:

  • 我不知道,我正在等待您的建议。
  • @petre:在不知道你为什么要这样做的情况下,很难给出更多建议。
  • 我喜欢 Jon Skeet 的回答在回答后 1 分钟内获得了三个 +1 - 甚至在他详细说明之前。一定很好:)
  • @Tim Irrating 更像 :-) 我认为他没有看到他一天内获得的大多数 +1 的好处,据我所知,达到了最大值。
  • @Adam 不要让乔恩听到你的声音,否则下一次计算机崩溃不会是 2002 年的遗留问题......
【解决方案2】:

如果您的目标是.Net 4.0,请使用dynamic 关键字代替BlahBlah,但如果您的目标较小,那么object 是您最安全的选择,因为它是您能想到的所有其他类的基类。

【讨论】:

    【解决方案3】:

    听起来这可能是generics 的一个好案例。如果您在调用它时知道期望的数据类型,则可以调用该函数的特定通用版本。

    【讨论】:

    • 虽然泛型可以在其他情况下提供帮助,但它在 OP 提供的情况下无济于事除非调用者知道将由提供的参数返回的类型编译时间...不太可能。
    • @Adam Houldsworth - 根据他对问题的描述(事实上这是一个从数据库返回值的调用),调用代码似乎实际上知道它所期望的。听起来他可能有一个 ReadFromDatabase(fieldname) 函数,在这种情况下您可能实际上知道该字段的数据类型。在我看来,这不是一个好的设计,但泛型会让它更容易。
    • 以 DataTable 中的 Field<T> 为例。唯一好的选择是这个或只是返回对象,并且由于 OP 排除了其他选项,这就是剩下的。
    • @Tim 同意,但删除强制转换选项可能会扩展到这样的情况。这实际上取决于调用代码的外观以及之后的预期用途。使用泛型只是在方法内部移动了转换,调用者仍然需要声明一个类型。
    【解决方案4】:

    考虑使用类似 Dapper-dot-net(由 Marc Gravell 和 Sam Saffron 在我们自己的 Stack Overflow 上编写)之类的东西从数据库中提取内容。它为您处理数据库到对象的映射。

    此外,如果您不想使用工具,并且从数据库中提取数据,并且您在编译时就知道各个列的数据类型(就像听起来一样),那么您可能应该是逐行而不是逐列工作。

    //Pseudo-code:
    List<DatabaseObject> objects = new List<DatabaseObject>();
    foreach(var row in DatabaseRows)
    {
        var toAdd = new DatabaseObject();
        toAdd.StringTypeVariable = "Demo";
        toAdd.IntTypeVariable = 2;
        toAdd.BoolTypeVariable = true;
        object.Add(toAdd);
    }
    

    注意:您可以在此处使用对象初始化器语法和 linq,但这是我能想到的最基本的演示方法,而无需使用大量额外的东西。

    另外请注意,这里我假设您实际上不想返回“Demo”、2 和 true,而是使用该行的值。这只是意味着您将硬编码值更改为:row.GetStringType(stringColumnIdx) 或类似的东西。

    【讨论】:

    • +1 表示逐行而不是逐列的建议
    【解决方案5】:

    使用返回类型为object,那么你可以得到任何返回类型。您必须通过反射或其他方法处理返回类型ether。

    检查一下:

    void Main()
    {
        object aa = VariableReturnExampleMethod(3);
        Console.WriteLine(aa.ToString());
    }
    
    object VariableReturnExampleMethod(int a)
    {
        if (a == 1)
            return "Demo";
        else if (a == 2)
            return 2;
        else if (a == 3)
            return true;
        else
            return null;
    }
    

    编辑: 我赞成强类型对象,你可以在 .net 平台上轻松实现它。

    if(returnedValue !=null)
    {
    
    string currentDataType = returnedValue.GetType().Name;
    object valueObj = GetValueByValidating(currentDataType, stringValue);
    }
    
    
     public object GetValueByValidating(string strCurrentDatatype, object valueObj)
            {
                if (valueObj != "")
                {
                    if (strCurrentDatatype.ToLower().Contains("int"))
                    {
                        valueObj = Convert.ToInt32(valueObj);
                    }
                    else if (strCurrentDatatype.ToLower().Contains("decimal"))
                    {
                        valueObj = Convert.ToDecimal(valueObj);
                    }
                    else if (strCurrentDatatype.ToLower().Contains("double") || strCurrentDatatype.ToLower().Contains("real"))
                    {
                        valueObj = Convert.ToDouble(valueObj);
                    }
                    else if (strCurrentDatatype.ToLower().Contains("string"))
                    {
                        valueObj = Convert.ToString(valueObj);
                    }
                    else
                    {
                        valueObj = valueObj.ToString();
                    }
                }
                else
                {
                    valueObj = null;
                }
                return valueObj;
            }
    

    【讨论】:

    • 他明确要求提供不强制转换的解决方案
    【解决方案6】:

    我看看你的问题,一个比第二个好,但最后我必须重写以更好地理解解决方案。这个解决方案跳过了很长的 if else stack 并在 Types 枚举上用 foreach 替换它,在那里我们可以实现我们需要的所有类型。我更喜欢使用动态,但这也可以使用。

    主函数GetValueByValidating如果类型已定义且可能返回值,其他情况返回false 看niranjan-kala这是你重写后的主要功能。

    
    
                /// 
            /// Enum of wanted types
            /// 
            public enum Types
            {
                [ExtendetFlags("int")]
                INT,
                [ExtendetFlags("decimal")]
                DECIMAL,
                [ExtendetFlags("double")]
                DOUBLE,
                [ExtendetFlags("real")]
                REAL,
                [ExtendetFlags("string")]
                STRING,
                [ExtendetFlags("object")]
                OBJECT,
                [ExtendetFlags("null")]
                NULLABLE
            }
            /// 
            /// Cycle by types when in enum exist string reference on type (helper)
            /// 
            /// 
            /// 
            public static Types GetCurrentType(string container)
            {
                foreach (Types t in Enum.GetValues(typeof(Types)))
                {
                    if (container.Contains(t.GetFlagValue()))
                    {
                        return t;
                    }
                }
                return Types.NULLABLE;
            }
            /// 
            /// Return object converted to type
            /// 
            /// 
            /// 
            /// 
            public static object GetValueByValidating(string strCurrentDatatype, object valueObj)
            {
                var _value = valueObj != null ? valueObj : null;
                try
                {
                    Types _current = _value != null ? GetCurrentType(strCurrentDatatype.ToLower()) : Types.NULLABLE;
    
                    switch (_current)
                    {
                        case Types.INT:
                            valueObj = Convert.ToInt32(valueObj);
                            break;
                        case Types.DECIMAL:
                            valueObj = Convert.ToDecimal(valueObj);
                            break;
                        case Types.DOUBLE:
                            valueObj = Convert.ToDouble(valueObj);
                            break;
                        case Types.REAL:
                            valueObj = Convert.ToDouble(valueObj);
                            break;
                        case Types.STRING:
                            valueObj = Convert.ToString(valueObj);
                            break;
                        case Types.OBJECT:
                            break;
                        case Types.NULLABLE:
                            throw new InvalidCastException("Type not handled before selecting, function crashed by retype var.");
                    }
                } catch (InvalidCastException ex)
                {
                    Log.WriteException(ex);
                    valueObj = false;
                }
    
                return valueObj;
            }
    
    
    

    【讨论】:

    猜你喜欢
    • 2016-06-19
    • 2022-12-17
    • 2013-09-28
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 2016-01-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多