[英]Generic C# Class: Set “Generic” Property
我对C#很陌生,所以我可能会遇到C#有一个简单解决方案的问题。 我有一个泛型类,属性为“generic”类型。 我想要一个函数来设置该属性,但我需要将其转换为这样做。
public class BIWebServiceResult<T>
{
public T Data;
public delegate StatusCode StringToStatusCode(string Input);
public void SetData(string Input, StringToStatusCode StringToError)
{
if (StringToError(Input) == 0)
{
if (Data is string[])
{
Data = new string[1];
Data[0] = Input;
}
else if (Data is string)
{
Data = Input;
}
else if (Data is bool)
{
Data = DetectBool(Input);
}
}
}
private bool DetectBool(string Compare)
{
return Compare == "true";
}
}
这种方法的问题是,它不起作用:)
(不,这不是所有代码,只是一个片段来显示我的问题)
它甚至没有编译,因为如果Data是 - 例如 - 布尔值,则“Data = new string []”不能工作。
如何根据我的通用属性的类型实现一个行为不同的函数?
您需要一个泛型类,但您正在根据其泛型类型参数更改其行为。
由于这种行为是根据T
专门设计的,因此您应该使您的泛型类成为一个抽象基础,从中派生专门的子类:
public abstract class BIWebServiceResult<T>
{
public T Data { get; set; }
public delegate StatusCode StringToStatusCode(string Input);
public abstract void SetData(string Input, StringToStatusCode StringToError);
}
然后你可能会,例如:
public class BIWebServiceStrArrayResult : BIWebServiceResult<string[]>
{
public override void SetData(string Input, StringToStatusCode StringToError)
{
if (StringToError(Input) == 0)
{
Data = new string[1];
Data[0] = Input;
}
}
}
但就个人而言,我倾向于完全取消所有这些手动字符串操作,并将解析输入的工作留给调用此方法的任何代码:
// This is the same signature used by, e.g., int.TryParse, double.TryParse, etc.
public delegate bool Parser<T>(string input, out T output);
public void SetData(string Input, Parser<T> parser)
{
T value;
if (parser(Input, out value))
Data = value;
}
顺便说一下,当Action
*或Func
*形式的相同签名已经可用时,通常不需要定义自己的委托。 对于StringToStatusCode
,可以简单地将其定义为Func<string, StatusCode>
。 (但我个人仍会推荐像我发布的最后一段代码。)
您可以尝试使用Convert.ChangeType()
方法:
Convert.ChangeType( input, typeof(T) );
但这只适用于Convert
类知道的类型。 转换为大多数自定义类型只会因InvalidCastException
而失败。
作为一般的实践,这不是构造泛型类的好方法。 泛型用于基于通用接口统一类型。 在您的情况下,该公共接口是您期望从字符串表示转换为泛型类型。
如果您确实需要支持将任意输入从string
转换为某种类型T
,则应该提供单独的泛型函数作为可以执行转换的类型的参数。 这是一个例子:
class BIWebServiceResult<T>
{
private readonly Func<string,T> m_ValueParser;
public BIWebServiceResult( Func<string,T> valueParser )
{
m_ValueParser = valueParser;
}
public void SetData(string Input, StringToStatusCode StringToError)
{
Data = m_ValueParser( Input ); // use supplied conversion func
//...
}
}
一种适用于简单类型的方法是使用TypeConverter。
T value = default(T);
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
if (converter.CanConvertFrom(typeof(string))
{
value = (T)converter.ConvertFrom(myString);
}
}
很难说这在你的场景中是否有用,但你可以为每种可能的数据类型使用子类,有点像:
public abstract class BIWebServiceResult<T>
{
public T Data;
public delegate void StringToStatusCode(string Input);
public abstract void SetData(string Input, StringToStatusCode StringToError);
}
public class StringBIServiceResult : BIWebServiceResult<string[]>
{
public override void SetData(string Input, StringToStatusCode StringToError)
{
Data = new string[1];
Data[0] = Input;
}
private bool DetectBool(string Compare)
{
return Compare == "true";
}
}
这样可以避免使用类型转换器,但可能会使你的类继承链变得过于复杂......
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.