为方法声明设置多个 return 值
set multiple return value for method declaration
我的函数如下:
public var UpdateMapFetcher(int stationID, int typeID)
我需要此函数来 return 字符串或整数。
我的return值设置如下
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;
}
如何在动态环境中将其中一种数据类型作为 return 值。
您可以 return 对象。您必须随后检查您的消费方法中的类型。我认为这在您的用例中不会成为问题。
因此您的方法签名是:
public object UpdateMapFetcher(int stationID, int typeID)
您可以 return 对象并转换为您想要的类型。
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;
}
您还可以选择使用 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);
}
坦率地说,我只是 return 一个元组,其中字符串为非 null 表示要使用的字符串值,null 作为 int return
的指示符
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
}
我的直觉告诉我,您正在尝试将字符串值转换为某种类型。在这种情况下,您可以使用:
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
}
我会选择 return 一个 object
的新 class
,它可能看起来像这样:
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
。您还可以通过验证值 get
来增强这一点。例如,对于 string
,它可能看起来像这样:
public string StringValue {
get {
if (IsString)
return m_stringValue;
throw new InvalidOperationException("Value is not a string.");
}
}
您不能真正完全那样做,但是有几种方法可以或多或少地完成您想要做的事情。不过,您最好稍微更改一下设计。
两个想法:
- 要么更改您的代码以使用两种不同的方法,然后根据需要分别调用它们。
- ..或return一个对象,你可以随心所欲地投射..
- ..或者,使用带有
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);
可以包含一种或另一种类型的类型通常称为(毫不奇怪)Either
。它是 sum type 的特例,基本上是 discriminated union、tagged union 或 disjoint union 恰好有两种情况(而不是任意数量)。
遗憾的是,标准库中不存在 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));
}
}
我的函数如下:
public var UpdateMapFetcher(int stationID, int typeID)
我需要此函数来 return 字符串或整数。
我的return值设置如下
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;
}
如何在动态环境中将其中一种数据类型作为 return 值。
您可以 return 对象。您必须随后检查您的消费方法中的类型。我认为这在您的用例中不会成为问题。
因此您的方法签名是:
public object UpdateMapFetcher(int stationID, int typeID)
您可以 return 对象并转换为您想要的类型。
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;
}
您还可以选择使用 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);
}
坦率地说,我只是 return 一个元组,其中字符串为非 null 表示要使用的字符串值,null 作为 int return
的指示符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
}
我的直觉告诉我,您正在尝试将字符串值转换为某种类型。在这种情况下,您可以使用:
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
}
我会选择 return 一个 object
的新 class
,它可能看起来像这样:
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
。您还可以通过验证值 get
来增强这一点。例如,对于 string
,它可能看起来像这样:
public string StringValue {
get {
if (IsString)
return m_stringValue;
throw new InvalidOperationException("Value is not a string.");
}
}
您不能真正完全那样做,但是有几种方法可以或多或少地完成您想要做的事情。不过,您最好稍微更改一下设计。
两个想法:
- 要么更改您的代码以使用两种不同的方法,然后根据需要分别调用它们。
- ..或return一个对象,你可以随心所欲地投射..
- ..或者,使用带有
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);
可以包含一种或另一种类型的类型通常称为(毫不奇怪)Either
。它是 sum type 的特例,基本上是 discriminated union、tagged union 或 disjoint union 恰好有两种情况(而不是任意数量)。
遗憾的是,标准库中不存在 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));
}
}