C#中方法的可变返回类型

11

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

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

我想要这样做的原因是,我有一个方法可以从数据库中读取一行中所选列的数据。这些列的类型并不相同,但我需要返回每个列的信息。


2
顺便提一句,除了所有这些的if-else语句之外,我建议你研究一下switch语句。http://msdn.microsoft.com/en-us/library/06tc147t(v=vs.80).aspx - RhysW
@RhysW +1 为用 switch,但在这种情况下也不需要 elseif 就足够了。 - Adam Houldsworth
你确定只需要返回一些标准类型,比如int、string等吗?还是需要从你的代码中返回更多的类? - nawfal
1
为什么不使用反射来处理对象?通常情况下,当您事先不知道要处理的数据时,这是最好的选择。 - svinja
http://blog.kjeldby.dk/2009/06/using-generic-methods-and-constrains/ - Sai Sherlekar
6个回答

18
如何从一个方法返回变量类型?我不想返回一个对象类型,然后再将其转换为另一种类型。 嗯,基本上你需要做的就是这样。或者,如果你使用的是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 版本之所以有效是因为它告诉了编译器将其正常工作 推迟 到运行时 - 所以你失去了通常使第二个示例在编译时失败的正常安全性。


我不知道,我在等待您的建议。 - sanchop22
@petre:如果不知道你最初为什么想要这样做,很难给出更多建议。 - Jon Skeet
2
我喜欢Jon Skeet的回答在他回答之后的1分钟内就获得了三个+1,甚至在他详细解释之前。真不错 :) - Tim
2
@Tim 更像是令人恼怒的 :-) 我认为他并没有看到他每天得到的大多数+1的好处,据我所知,他经常达到最大值。 - Adam Houldsworth
1
@Adam,别让Jon听到你说这话,否则下一次电脑崩溃可不是2002年的遗留问题了... - Sinjai

4

如果你的目标是.Net 4.0,那么使用dynamic关键字代替BlahBlah,但如果版本较低,则object是最保险的选择,因为它是其他所有类的基类。


2

看起来这可能是使用泛型的好例子。如果你知道在调用函数时期望的数据类型,你可以调用该特定泛型版本的函数。


尽管泛型在其他情况下可能有所帮助,但在OP提供的情况下,除非调用者在编译时知道由参数提供的返回类型,否则它不会有所帮助...这是不太可能的。 - Adam Houldsworth
基于他描述的问题(即这是一个从数据库返回值的调用),似乎调用代码可能实际知道它期望什么。听起来可能有一个 ReadFromDatabase(fieldname)函数,并且在这种情况下你可能真的知道字段的数据类型。 在我看来,这不是一个好的设计,但泛型会使它变得更容易。 - Tim
考虑 Field<T> 从 DataTable 中作为一个例子。唯一的好选择是这个或者只返回对象,由于 OP 排除了其他选项,这就是剩下的选择。 - Servy
@Tim 同意,但是移除转换选项可能会导致类似这样的情况。这实际上取决于调用代码的外观以及之后的预期使用方式。使用泛型只是将转换移到方法内部,调用者仍然需要声明一个类型。 - Adam Houldsworth

2
考虑使用像Dapper-dot-net这样的工具(由我们自己的Stack Overflow的Marc Gravell和Sam Saffron编写)从数据库中提取数据。它会为你处理数据库到对象的映射。
此外,如果您不想使用工具,并且您正在从数据库中提取数据,并且在编译时知道各列的数据类型(就像您所说的那样),则应该按行而不是按列进行操作。
//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)或类似的内容。

推荐逐行而非逐列进行操作,对此点赞。 - Bob2Chiv

0

我看了你的要求,其中一个比另一个更好,但最后我必须重写以更好地理解解决方案。这个解决方案跳过了长长的if else堆栈,并用Types枚举上的foreach替换它,我们可以在那里实现所有需要的类型。我更喜欢使用dynamic,但这也是可用的。

主函数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;
        }



这是来自枚举的ExtendedFlags的承诺代码: ExtendedFlags类 - Michael Gordon

0

使用返回类型为object,然后您就可以获得任何返回类型。您必须通过反射或其他方法处理返回类型。

请检查:

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;
        }

他明确要求一个不需要强制类型转换的解决方案。 - Chris Pfohl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接