Generic C # Class: Set the Generic Property

I am new to C #, so I may have a problem with C # having a simple solution. I have a generic class with the property "generic". I want to have a function to set this property, but I need to convert it to do this.

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

The problem with this approach is that it does not work :)

(No, that is not all the code, just a snippet to show that my problem is)

It does not even compile because "Data = new string []" cannot work if Data - for example - boolean.

How to implement a function that behaves differently depending on the type of my common property?

+3
source share
4 answers

, generic.

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>. ( - , .)

+4

Convert.ChangeType():

Convert.ChangeType( input, typeof(T) );

, Convert. InvalidCastException.

, . Generics . , .

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
        //...
    }
}
+3

An approach that will work for simple types is to use TypeConverter.

T value = default(T);
TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
if (converter != null)
{
    if (converter.CanConvertFrom(typeof(string))
    {
        value = (T)converter.ConvertFrom(myString);
    }
}
+2
source

It's hard to say if this would make sense in your scenario, but you can probably use a child class for each of the possible data types, something like:

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

this avoids the use of customization and the use of type converters, but can lead to the fact that your chain of class inheritance will be overly complex ...

+1
source

Source: https://habr.com/ru/post/1749649/


All Articles