Home > database >  How to use "myFunc(Func<T>) where T : class" as well as "myFunc(Func<bool>
How to use "myFunc(Func<T>) where T : class" as well as "myFunc(Func<bool>

Time:11-01

Background:

To get rid I of redundant code I am using strategy pattern. So I placed this (former) redundant code into context class of strategy pattern, where method IsSuccess ProcessApiMethod() will be called. Context class ist not where my problems lies, I just show it to you for completeness.

Difficulty:

  • Method ProcessApiMethod() shall return null if TOut is a class.
  • But TOut could be a basic type like int or bool, too.

So far solved:

  • Further, some API-methods will have return type void. This is why I implemented two different interfaces.

My Problem - It lies where the difficutly is:

  • Does C# allow alternate generic constraints?
  • And how to just allow basic types as possible types of T?

I miss something like the following ...

public interface ISuccessConverterStrategy<TOut> where Tout : (class || basicType)

But this would not make any sense:

public interface ISuccessConverterStrategy<TOut> where Tout : (class || (!class && !struct))
  • If "No" is your answer to my first question: How can I solve this problem?

At the moment, no matter how I tried it, in my strategy classes compiler tells me "Interface member 'TOut SuccessConverter.ISuccessConverterStrategy.GetResult()' is not implemented" or he mentions another problem with usage of those generics.

This ist my full code for completeness:

public enum IsSuccess
{
   No = - 1,
   NotSupported = 0,
   Yes = 1,
   WithoutContent = 2
}

/// <sumary>
/// Interface of Strategy Pattern
/// </summary>
public interface ISuccessConverterStrategy
{
   IsSuccess ProcessApiMethod();
}
    
public interface ISuccessConverterStrategy<TOut> : ISuccessConverterStrategy
{
   /// <summary>
   /// After processing 
   /// Returns null, if processing method has no return value.
   /// Returns null, if something went wrong.
   /// Returns return value, otherwise.
   /// </summary>
   /// <typeparam name="TOut"></typeparam>
   /// <returns></returns>
   TOut GetResult<TOut>();
}

/// <summary>
/// Context class of strategy pattern.
/// </summary>
public class SilentSuccessConverter
{
   /// <summary>
   /// Silences API-method when called within strategy-method. Extends range of possible return values
   /// of type IsSuccess, e.g. by IsSuccess.NotSupported. Catches possible exception messages.
   /// </summary>
   /// <param name="strategy"></param>
   /// <param name="errorMessage"></param>
   /// <returns></returns>
   /// <exception cref="NullReferenceException"></exception>
   public IsSuccess Convert(ISuccessConverterStrategy strategy, out string errorMessage)
   {
       if (null == strategy)
       {
           throw new NullReferenceException(nameof(strategy));
       }

       errorMessage = "";

       try
       {
           return strategy.ProcessApiMethod();
       }
       catch (Exception e) when (e.Message.ToLower().Contains("not implemented"))
       {
           errorMessage = $" - Message: {e.Message} - Source: {e.Source}"   Environment.NewLine;
           return IsSuccess.NotSupported;
       }
       catch (Exception e)
       {
           errorMessage = $" - Message: {e.Message} - Source: {e.Source}"   Environment.NewLine;                
        
           if (e is NotImplementedException || e is NotSupportedException)
           {
               return IsSuccess.NotSupported;
           }
        
           return IsSuccess.No;
       }
   }   
}

public class FuncTOutClassStrategy<TOut> : ISuccessConverterStrategy<TOut> where TOut : class
{
   private Func<TOut> _apiMethod;
   private TOut _result;

   /// <summary>
   /// Holds a method without parameters, which returns an generic class object.
   /// </summary>
   /// <param name="apiMethod"></param>
   public void SetApiMethod(Func<TOut> apiMethod)
   {
      _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
   }
        
   public IsSuccess ProcessApiMethod()
   {
      _result = _apiMethod();
      return null != _result ? IsSuccess.Yes : IsSuccess.No; 
   }

   public TOut GetResult()
   {
      return _result;
   }
}

public class FuncIntOutStrategy<int> : ISuccessConverterStrategy<int> 
{
    private Func<int> _apiMethod;
    private int _result;

    /// <summary>
    /// Holds a method without parameters, which returns int.
    /// </summary>
    /// <param name="apiMethod"></param>
    public void SetApiMethod(Func<int> apiMethod)
    {
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }
    
    public IsSuccess ProcessApiMethod()
    {
        _result = _apiMethod();
        return _result > 0 ? IsSuccess.Yes : IsSuccess.No; 
    }

    public int GetResult()
    {
        return _result;
    }
}

public class ActionTInStrategy<TIn> : ISuccessConverterStrategy 
{
    private Action<TIn> _apiMethod;
    private TIn _input;

    /// <summary>
    /// Holds a void method that receives an object of type T.
    /// </summary>
    /// <param name="apiMethod"></param>
    /// <param name="input"></param>
    public void SetApiMethod(Action<TIn> apiMethod, TIn input)
    {
        _input = input;
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }

    public IsSuccess ProcessApiMethod()
    {
        _apiMethod(_input);
        return  IsSuccess.Yes; 
    }
}

public class ActionStrategy : ISuccessConverterStrategy
{
    private Action _apiMethod;

    /// <summary>
    /// Holds a void method without any parameters.
    /// </summary>
    /// <param name="apiMethod"></param>
    public void SetApiMethod(Action apiMethod)
    {
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }

    public IsSuccess ProcessApiMethod()
    {
        _apiMethod();
        return  IsSuccess.Yes; 
    }
}

CodePudding user response:

Now I think I got it without errors. These are those code parts I modified:

public interface ISuccessConverterStrategy<out TOut> : ISuccessConverterStrategy 
{
   /// <summary>
   /// After processing 
   /// Returns null, if processing method has no return value.
   /// Returns null, if something went wrong.
   /// Returns return value, otherwise.
   /// </summary>
   /// <typeparam name="TOut"></typeparam>
   /// <returns></returns>
   TOut GetResult();
}

public class FuncBoolOutStrategy : ISuccessConverterStrategy<bool>
{
    private Func<bool> _apiMethod;
    private bool _result;

    /// <summary>
    /// Holds a method without parameters, which returns bool.
    /// </summary>
    /// <param name="apiMethod"></param>
    public void SetApiMethod(Func<bool> apiMethod)
    {
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }
    
    public IsSuccess ProcessApiMethod()
    {
        _result = _apiMethod();
        return _result ? IsSuccess.Yes : IsSuccess.No; 
    }

    public bool GetResult()
    {
        return _result;
    }
}

public class FuncIntOutStrategy : ISuccessConverterStrategy<int> 
{
    private Func<int> _apiMethod;
    private int _result;

    /// <summary>
    /// Holds a method without parameters, which returns int.
    /// </summary>
    /// <param name="apiMethod"></param>
    public void SetApiMethod(Func<int> apiMethod)
    {
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }
    
    public IsSuccess ProcessApiMethod()
    {
        _result = _apiMethod();
        return _result > 0 ? IsSuccess.Yes : IsSuccess.No; 
    }

    public int GetResult()
    {
        return _result;
    }
}

public class FuncTOutClassStrategy<TOut> : ISuccessConverterStrategy<TOut>  where TOut : class
{
    private Func<TOut> _apiMethod;
    private TOut _result;

    /// <summary>
    /// Holds a method without parameters, which returns an generic class object.
    /// </summary>
    /// <param name="apiMethod"></param>
    public void SetApiMethod(Func<TOut> apiMethod)
    {
        _apiMethod = apiMethod ?? throw new NullReferenceException(nameof(apiMethod));
    }
    
    public IsSuccess ProcessApiMethod()
    {
        _result = _apiMethod();
        return null != _result ? IsSuccess.Yes : IsSuccess.No; 
    }

    public TOut GetResult()
    {
        return _result;
    }
}

Maybe you find something to improve, like necessary constraints or ... .

  • Related