0
{
    public class MyClass
    {
        // all the call to GetData() of apiHelper should pass through this method
        public async Task<T> InitiateAPICallAsync<T>(Task<T> apiCall) where T : BaseResponse
        {
            var response = await apiCall;
            // some common code work using response data
            return response;
        }

        public async void MyFunc()
        {
            var helper = new APIHelper("1", "2");
            //
            var response1 = await InitiateAPICallAsync(helper.GetData<Response1>()); // correct way
            var rewponse2 = await helper.GetData<Response1>(); // incorrect way, need to show warning
        }
    }


    public class APIHelper
    {
        public APIHelper(string a, string b)
        {
            // some code
        }

        public async Task<T> GetData<T>()
        {
            await Task.Delay(1000); // network call
            // other code
            return default;
        }
    }

    public class Response1 : BaseResponse { }

    public class Response2 : BaseResponse { }

    public class BaseResponse { }
}

in my application MyClass, there is a method named InitiateAPICallAsync(). All call to the GetData() method of APIHelper must be pass through this method. I need to showing warning, if GetAsync() method called directly without passing through InitiateAPICallAsync.

Note: It is a sample code snippet, where in my real time project the APIHelper represents a Connectivity library. and MyClass represents another library named service.

NAVEEN V
  • 42
  • 6
  • Does this answer your question? [How can I find the method that called the current method?](https://stackoverflow.com/questions/171970/how-can-i-find-the-method-that-called-the-current-method) – Fumeaux Aug 10 '20 at 17:59
  • 2
    Why not make `APIHelper` inaccessible and generate a wrapper type instead that always goes through `InitiateAPICallAsync`? Making things impossible (or unattractive) to do in the first place is better than detecting them and issuing warnings. – Jeroen Mostert Aug 10 '20 at 18:01
  • @JeroenMostert Can you please provide a code snippet or alter my code snippet for better understanding ? – NAVEEN V Aug 10 '20 at 18:07
  • Move `InitiateAPICallAsync` to its own class (`APIHelper2`, I'm not creative) and have callers then use `await helper2.GetData()`, where `helper2` just calls `await initiateAPICallAsync(helper.GetData())`. Doing this for lots of methods gets tedious, of course, but you can use code generation (T4 templates or something else) to generate this wrapping code, and you can use delegates and/or reflection to call the inner helper methods if you so prefer. – Jeroen Mostert Aug 10 '20 at 18:15
  • @JeroenMostert Sorry, i didn't get it clearly. If you are asking to move `InitiateAPICallAsync` to `APIHelper` (connectivity library), it is not possible. Because the functionality in `InitiateAPICallAsync` cannot be done in connectivity library. Also making the `APIHelper` inaccessible is not possible one, because its a library class which holds many methods. Where my case is only for specific method 'GetData()'. Thats why i need to show a warning by using custom attribute (like Obsolete) for `GetAsync()` or custom warning rule set if possible. – NAVEEN V Aug 10 '20 at 18:33
  • Have you tried add custom warning for GetData method `[Obsolete("Please make it as paramter for InitiateAPICallAsync(helper.GetData())")]` ? – Nico Zhu Aug 11 '20 at 03:21
  • @NicoZhu-MSFT i have tried it. If i add `Obsolete` to `GetData()` method, then it will show warning even if i pass it through `InitiateAPICallAsync` – NAVEEN V Aug 11 '20 at 05:29
  • Yep, it will show the warning for all, you could add the specific description to told developer, if you have done above please ignore the warning message. – Nico Zhu Aug 11 '20 at 07:07
  • @NicoZhu-MSFT This method is one of the frequently using methods in my project. Showing warning for all call will make the code looks untidy. – NAVEEN V Aug 11 '20 at 07:16
  • Yep, I also tried use CallerMemberName attribute to get the caller, but the result is `MyFunc` but not `InitiateAPICallAsync`. – Nico Zhu Aug 11 '20 at 07:22

1 Answers1

0

How to show warning for a method if it is called directly in c#

Using CallerMemberName attribute is core thread of the following solution, thanks for Fumeaux's comment, I tried place CallerMemberName attribute above GetData method directly to get the caller, but the result is MyFunc but not InitiateAPICallAsync. So I tried use delegate as the InitiateAPICallAsync parameter that could make sure GetData will called by InitiateAPICallAsync. The following code has been simplified.

public delegate Task<int> PrintCaller([CallerMemberName] string Caller = null);
public class MyClass
{
    public async Task<string> InitiateAPICallAsync(PrintCaller apiCall)
    {
        var response = await apiCall();
        return "Test";
    }

    public async void MyFunc()
    {
        var helper = new APIHelper();
        var str1 = await InitiateAPICallAsync(new PrintCaller(helper.GetData));
        var str2 = await helper.GetData();
    }
}
public class APIHelper
{      
    public async Task<int> GetData([CallerMemberName] string Caller = null)
    {
        if (Caller == "InitiateAPICallAsync")
        {
            // do some thing
        }
        else
        {
            //Show Warning
            var dialog = new MessageDialog("Waring!!! Please don't call it directly");
            await dialog.ShowAsync();
        }

        return 0;
    }
}
Nico Zhu
  • 32,367
  • 2
  • 15
  • 36
  • Thanks for the Answer. I'll consider this as one of the answers. But my requirement is to show warning during development or compilation time like Obsolete attribute or code analysis rules did. Is it possible to achieve? – NAVEEN V Aug 11 '20 at 12:54
  • I'm afraid you can't do it at precompiled time, because we need use `CallerMemberName` attribute to get the caller, however Attribute queried at run time. – Nico Zhu Aug 11 '20 at 15:49