【问题标题】:set multiple return value for method declaration为方法声明设置多个返回值
【发布时间】:2016-08-22 05:26:56
【问题描述】:

我的功能如下:

  public var UpdateMapFetcher(int stationID, int typeID)

我需要这个函数来返回字符串或整数。

我的返回值设置如下

 if (finaloutput == "System.String")
        {
            // param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
            returnvalue = returnvalue.ToString();
            return returnvalue;
        }
        else if (finaloutput == "System.Int32")
        {
            int a=0;
            a = Convert.ToInt32(returnvalue);
            return a;
        }

如何在动态环境中将任一数据类型作为返回值。

【问题讨论】:

  • 你能更好地描述一下为什么你需要这个吗? (你可以随时返回object,但我认为也许你应该重新考虑一下设计)
  • var 只是“编译器,请找出正确的数据类型并放在这里”。它仍然需要在编译时确定

标签: c# methods svc


【解决方案1】:

我的直觉告诉我,您正在尝试将字符串值转换为某种类型。在这种情况下,您可以使用:

public T UpdateMapFetcher<T>(int stationID)
{
    //var someValue = "23";
    return (T)Convert.ChangeType(someValue, typeof(T));
}
//then
var typed = UpdateMapFetcher<int>(6);

如果你不知道T,你可以使用映射(0-int、1-string等):

public object UpdateMapFetcher(int stationID, int type)
{
    var typeMap = new []{ typeof(int), typeof(string)};
    //var someValue = "23";
    return Convert.ChangeType(someValue, typeMap[type]);
}
//then
var untyped = UpdateMapFetcher(6, 0/*0 is int*/);
if (untyped.GetType() == typeof(int))
{ /*is int*/
}

另一种解决方案是使用隐式转换:

public class StringOrInt
{
    private object value;
    public ValueType Type { get; set; }

    public static implicit operator StringOrInt(string value)
    {
        return new StringOrInt()
        {
            value = value,
            Type = ValueType.String
        };
    }
    public static implicit operator StringOrInt(int value)
    {
        return new StringOrInt()
        {
            value = value,
            Type = ValueType.Int
        };
    }
    public static implicit operator int(StringOrInt obj)
    {
        return (int)obj.value;
    }
    public static implicit operator string(StringOrInt obj)
    {
        return (string)obj.value;
    } 
}
public enum ValueType
{
    String,
    Int
}

然后(简化):

public static StringOrInt UpdateMapFetcher(int stationID, int typeID)
{
    if (typeID == 0)
        return "Text";
    return 23;
}

private static void Main(string[] args)
{
    var result = UpdateMapFetcher(1, 1);
    if (result.Type == ValueType.String) { }//can check before
    int integer = result;//compiles, valid
    string text = result;//compiles, fail at runtime, invalid cast      
}

【讨论】:

    【解决方案2】:

    你可以返回一个对象。您必须随后检查消费方法中的类型。我认为这在您的用例中不会成为问题。

    因此,您的方法签名是:

    public object UpdateMapFetcher(int stationID, int typeID)
    

    【讨论】:

      【解决方案3】:

      您还可以选择使用out keyword,它允许您将两者都接受到变量中并在调用函数后进行检查。

      public void UpdateMapFetcher(int stationID, int typeID, out int intValue, out string strValue)
      
      // or int return val and out string value
      
      public int UpdateMapFetcher(int stationID, int typeID, out string strValue)
      

      使用看起来像这样:

      int intVal;
      string strVal;
      
      UpdateMapFetcher(stationID, typeID, out intVal, out strVal);
      
      if (strVal != null) 
      { 
          doSomethingWithString(strVal); 
      }
      else
      {
          doSomethingWithInt(intVal);
      }
      

      【讨论】:

        【解决方案4】:

        坦率地说,我只返回一个元组,字符串为非空值,表示要使用的字符串值,空值作为 int 返回的指示符

        public Tuple<string, int> UpdateMapFetcher(int stationID, int typeID) {
            if (finaloutput == "System.String")
            {
                // param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
                returnvalue = returnvalue.ToString();
                return new Tuple<string, int>(returnvalue, 0);
            }
            else if (finaloutput == "System.Int32")
            {
                int a=0;
                a = Convert.ToInt32(returnvalue);
                return new Tuple<string, int>(null, a);
            }
        
        }
        

        消费者方面

        var rc = UpdateMapFetcher( .... );
        
        if (rc.Item1 != null) {
            // code to use string value
        } else {
           // code to use int value
        }
        

        【讨论】:

          【解决方案5】:

          我会选择返回一个新的classobject,它可能看起来像这样:

          class Result {
          
              public string StringValue { get; }
          
              public string Int32Value { get; }
          
              public bool IsString { get; }
          
              public bool IsInt32 { get; }
          
              public Result(string value) {
                  StringValue = value;
                  IsString = true;
              }
          
              public Result(int value) {
                  Int32Value = value;
                  IsInt32 = true;
              }
          }
          

          通过这种方式,您可以使用Isxxx 属性检查是哪个Type。您还可以通过验证值geters 来增强此功能。例如,对于string,它可能看起来像这样:

          public string StringValue {
              get {
                  if (IsString)
                      return m_stringValue;
                  throw new InvalidOperationException("Value is not a string.");
              }
          }
          

          【讨论】:

            【解决方案6】:

            你不能真正做到完全,但是有几种方法可以或多或少地做你想做的事。不过,你可能会更好地改变设计。

            两个想法:

            • 要么更改您的代码以使用两种不同的方法,然后根据需要分别调用它们。
            • ..或者返回一个对象,你可以随意转换它..
            • ..或者,使用带有TypeDescriptor 的通用方法,如下所示。

            请注意,我们在这里首先将值转换为字符串,即使它是一个 int,因为我们可以使用通用方法 ConvertFromString() 将其转换为 T 的任何类型。

            public T UpdateMapFetcher<T>(int stationID, int typeID) {
                // To allow parsing to the generic type T:
                var converter = System.ComponentModel.TypeDescriptor.GetConverter(typeof(T));
                if(converter != null)
                {
                    return (T)converter.ConvertFromString(returnvalue.ToString());
                }    
                else
                {
                    return default(T);
                }
            }
            

            用法:

            var result = MyExtensions.UpdateMapFetcher<string>(1, 2);
            

            或:

            var result = MyExtensions.UpdateMapFetcher<int>(1, 2);
            

            【讨论】:

              【解决方案7】:

              您可以返回 Object 并转换为您想要的类型。

              public Object UpdateMapFetcher(int stationID, int typeID)
              
              if (finaloutput == "System.String")
                      {
                          // param1[i] = Convert.ChangeType(typeID_New.ToString(), typeof(string));
                          returnvalue = returnvalue.ToString();
                          return returnvalue;
                      }
                      else if (finaloutput == "System.Int32")
                      {
                          int a=0;
                          a = Convert.ToInt32(returnvalue);
                          return a;
                      }
              

              【讨论】:

                【解决方案8】:

                可以包含一种或另一种类型的类型通常称为(毫不奇怪)Either。它是sum type 的特例,基本上是可区分联合标记联合不相交联合,只有两种情况(而不是任意数字)。

                不幸的是,标准库中不存在 Either 类型的实现,但在 Google、GitHub 和其他地方可以找到很多实现......并从例如移植现有实现之一。 Haskell 或 Scala 也没有那么难。

                看起来有点像这样(原谅我的代码,我实际上不太了解 C♯):

                using System;
                
                abstract class Either<A, B>
                {
                    public abstract bool IsLeft { get; }
                    public abstract bool IsRight { get; }
                    public abstract A Left { get; }
                    public abstract B Right { get; }
                    public abstract A LeftOrDefault { get; }
                    public abstract B RightOrDefault { get; }
                    public abstract void ForEach(Action<A> action);
                    public abstract void ForEach(Action<B> action);
                    public abstract void ForEach(Action<A> leftAction, Action<B> rightAction);
                
                    private sealed class L : Either<A, B>
                    {
                        private A Value { get; }
                        public override bool IsLeft => true;
                        public override bool IsRight => false;
                        public override A Left => Value;
                        public override B Right { get { throw new InvalidOperationException(); } }
                        public override A LeftOrDefault => Value;
                        public override B RightOrDefault => default(B);
                        public override void ForEach(Action<A> action) => action(Value);
                        public override void ForEach(Action<B> action) {}
                        public override void ForEach(Action<A> leftAction, Action<B> rightAction) => leftAction(Value);
                
                        internal L(A value) { Value = value; }
                    }
                
                    private sealed class R : Either<A, B>
                    {
                        private B Value { get; }
                        public override bool IsLeft => false;
                        public override bool IsRight => true;
                        public override A Left { get { throw new InvalidOperationException(); } }
                        public override B Right => Value;
                        public override A LeftOrDefault => default(A);
                        public override B RightOrDefault => Value;
                        public override void ForEach(Action<A> action) {}
                        public override void ForEach(Action<B> action) => action(Value);
                        public override void ForEach(Action<A> leftAction, Action<B> rightAction) => rightAction(Value);
                
                        internal R(B value) { Value = value; }
                    }
                
                    public static Either<A, B> MakeLeft(A value) => new L(value);
                    public static Either<A, B> MakeRight(B value) => new R(value);
                }
                

                你会这样使用它:

                static class Program
                {
                    public static void Main()
                    {
                        var input = Console.ReadLine();
                        int intResult;
                        var result = int.TryParse(input, out intResult) ? Either<int, string>.MakeLeft(intResult) : Either<int, string>.MakeRight(input);
                        result.ForEach(r => Console.WriteLine("You passed me the integer one less than " + ++r), r => Console.WriteLine(r));
                    }
                }
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2013-02-02
                  • 2022-12-17
                  • 2015-12-14
                  • 2015-07-14
                  • 1970-01-01
                  • 2013-11-08
                  • 2017-08-30
                  相关资源
                  最近更新 更多