簡體   English   中英

通用C#類:設置“通用”屬性

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM