Casting Func<> into delegate

Hi Guys,

I’m trying to cast Func<>'s into a delegate. Can anyone help please?

private delegate WWW QueryAction(params string[] data);

private Dictionary<string, QueryAction> querys;

        private void Awake()
        {
            //Func<int> myDelegate = () => 1 + 2 + a + b;
            WWW ss;
            querys = new Dictionary<string, QueryAction>();
            querys.Add(RequestType.Login.ToString(), (QueryAction)Func<string, string, WWW> ss = (a, b) => a ); // <-- This doesn't work. I want to choose the number of parameters for each <key, value> pair to make dynamic queries
            querys.Add(RequestType.ContactInfo.ToString(), (((d) => new WWW(""))));
        }

I’m doing this because Func<>'s can’t have params, but delegates can. So I want to cast static argument Func<>'s into the delegate.

Thanks!

Not quite sure I’m getting what you’re trying to do. You can’t cast a Func to a queryAction because none of the Func delegates have param arguments. But what do you need the Func’s for in the first place?

Say you have a method like this:

private static WWW Foo(string s1, string s2) {
    return new WWW(s1 + s2);
}

or a declared Func like this:

private static Func<string, string, WWW> Foo;

To add that to your queries, you’ll have to unpack it:

queries["Foo"] = data => Foo(data[0], data[1])

But that makes you lose code safety - you can now call Foo with the wrong number of arguments:

queries["Foo"]("bar");

And get an IndexOutOfRange.

Am I not understanding what you’re trying to do?

Btw:
“querys” should really be a Dictionary<RequestType, QueryAction>, unless I’m missing something. And it should also be named “queries”!

Thanks for coming back to me Baste. I’m trying to refactor a dirty switch statement:

        public IEnumerator MakeRequest(RequestType reqType, Action<object> result, params string[] sendInfo)
        {
            TopMenuManager.managerInstance.loadingAnimation = true;

            WWW www = GetQuery(reqType, sendInfo); // Here I'd prefer a Dictionary(enum RequestType, Action with params that return a new WWW)

            #if DEBUG || DEVELOPMENT_BUILD
            Debug.Log(www.url);
            #endif

            yield return www;

            TopMenuManager.managerInstance.loadingAnimation = false;

            #if DEBUG || DEVELOPMENT_BUILD
            Debug.Log(www.text);
            #endif

            // Turn off visually when not connected to internet
            TopMenuManager.managerInstance.internetConnection = !HasError(www);

            result(HandleReturnData(reqType, www));
        }

// This is what I want to change is this massive method.

        private WWW GetQuery(RequestType reqType, params string[] sendData)
        {
            switch (reqType)
            {
                case RequestType.Login:
                    {
                        #if DEBUG || DEVELOPMENT_BUILD
                        // Test Login - For debugging only
                        if (username.text.Length < 1)
                        {
                            username.text = "a.user@somewhere.com";
                            password.text = "testPassword";
                        }
                        #endif

                        return new WWW( url + "login.php?username=" + username.text + "&password=" + password.text.Replace("&", "%26"));
                    }
                case RequestType.SongList:
                    {
                        return new WWW(url + songsList + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.ContactInfo:
                    {
                        return new WWW(url + api + contactQuery + '"' + username.text + '"' + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.Sessions:
                    {
                        return new WWW(url + api + sessionQuery + "=%2520%22" + sendData[0] + "%22" + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.Venues:
                    {
                        return new WWW(url + api + venueQuery + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.Groups:
                    {
                        return new WWW(url + api + Group + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.Create:
                    {
                        return new WWW(url + createQuery + sendData[0] + "&qrdata=" + sendData[1] + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.Download:
                    {
                        //Dictionary<string, string> headers = new Dictionary<string, string>();

                        //headers.Add("url", "https://rest/2.0/Document/" + sendData[0]);
                        //headers.Add("name", sendData[1]);
                        //headers.Add("token", CleanEntry(userInfo["SessionId"]));

                        return new WWW(url + apiDownload + sendData[0] + "&name=" + sendData[1] + "&url=" + url + token + CleanEntry(userInfo["SessionId"]));//, null, headers);
                    }
                case RequestType.EmergencyContact:
                    {
                        return new WWW(url + api + "query%3Fq%3DFROM%2520Force.Emergency_Contact" + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.UpdatePersonalInfo:
                    {
                        return new WWW(url + "UpdateData.php?FirstName=" + sendData[0] + "&LastName=" + sendData[1] + "&Email=" + sendData[2] + "&Name=" + sendData[0] + " " + sendData[1] + "&OtherState=" + sendData[3] + "&OtherStreet=" + sendData[4] + "&Birthdate=" + sendData[5] + "&OtherCity=" + sendData[6] + "&OtherCountry=" + sendData[7] + "&OtherPostalCode=" + sendData[8] + "&Phone=" + sendData[9] + "&Id=" + sendData[10] + "&Voice_Type__c=" + sendData[11] + "&Gender__c=" + sendData[12] + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.BillingHistory:
                    {
                        return new WWW(url + api + "query%3Fq%3DFROM%2520Force.Force%2520WHERE%2520Status__c%2520!=%2520\"Pending\"" + token + CleanEntry(userInfo["SessionId"]));
                    }
                case RequestType.SessionCalendar:
                    {
                        return new WWW(url + "SessionList.php?url=" + "query%3Fq%3DFROM%2520Attendance" + token + CleanEntry(userInfo["SessionId"]));
                    }
                default:
                    {
                        return null;
                    }
            }
        }

and this is where it’s called:

            // Login request
            JSONObject loginData = null;
            yield return StartCoroutine( serviceManager.MakeRequest(RequestType.Login, value => loginData = value as JSONObject));

            JSONObject contactData = null;
            // Contact info request
            if (loginData != null && loginData.HasField("SessionId") && !loginData["SessionId"].IsNull && loginData["IsSuccess"] == true)
            {
                yield return StartCoroutine( serviceManager.MakeRequest(RequestType.ContactInfo, value => contactData = value as JSONObject) );
            }

Those refactors you mentioned at the bottom are right, thanks for the reminder.

First off… Func<> is a delegate (well technically Func<> isn’t, because there needs to be a result type generic… Func is a delegate, Func<> doesn’t exist):

Next, there are generic versions of the Func<> delegate that takes different numbers of parameters:
2 param

3 param

4 param

etc

Note, each of these are DISTINCT types. They all happen to have similar names. Func is not interachangeable with Func<T1, TResult>… they could just as easily be called ‘FuncWithNoParams’ and ‘FuncWithOneParam<T1, TResult>’.

Your delegate on the other hand is of type ‘QueryAction’

private delegate WWW QueryAction(params string[] data);

To say “cast Func<> into a delegate” is like saying “cast MonoBehaviour into a class”. They are already that.

What you mean is you want to cast a delegate from one type to the other. Like casting MonoBehaviour to Component.

Problem is… you can’t.

In your situation it’d be like casting a MonoBehaviour to a Rect… they’re 2 completely different types. One takes in an array of strings and outputs a WWW, the other takes in 2 strings and outputs a WWW.

Thing is… you’re also using anonymous/lambda functions to do this. These are anonymous. Just remove the whole ‘Func<string,string,WWW>’ bit and let it be a QueryAction, you’ll just have to shape the input parameters appropriately (accepting a params array, rather than 2 independent strings).

So really, all you need is to do this:

private delegate WWW QueryAction(string[] data);

...

querys = new Dictionary<string, QueryAction>();
querys.Add("test", (data) => {
    return new WWW(data[0]); //I don't know what you want here
});
1 Like