So I've currently got a little collection of methods to wrap the Unity WWW class; HandleTexture, HandleText, HandleBytes... but it's a lot of copy-pasted waste. I'm trying to wrap it all up under a generic HandleResult method that hands things off to _HandleResult under the hood. At this point the C# compiler complains about being unable to statically type T to Texture (each of the lines with closure(...);
private IEnumerator _HandleResult<T> (System.Action<T> closure, System.Action<string> onError){
yield return webRequest;
// Can't do a switch statement on Type, needs to be if/else chain :(
if (SuccessWithoutErrors(onError)) {
if(typeof(T) == typeof(Texture))
closure(webRequest.texture);
else if(typeof(T) == typeof(string))
closure(webRequest.text);
else if(typeof(T) == typeof(MovieTexture))
closure(webRequest.movie);
else if(typeof(T) == typeof(byte[]))
closure(webRequest.bytes);
else
throw new System.NotSupportedException("Could not interpret response data as " + typeof(T).Name + ". Supported types include Texture, MovieTexture, byte[] and string.");
}
}
I've been stuck at this point for a bit now. I'm fairly new to C# so maybe what I'm going for isn't feasible at all. Would greatly appreciate input from people who know more about the type system or what alternatives I should look into to achieve the same effect in terms of code duplication reduction.
C# doesn't seem to like it if you cast directly to a generic type. But you can cast to object
first, then cast to the generic type:
private IEnumerator _HandleResult<T> (System.Action<T> closure, System.Action<string> onError){
yield return webRequest;
if (SuccessWithoutErrors(onError)) {
if(typeof(T) == typeof(Texture))
closure((T)(object)webRequest.texture);
else if(typeof(T) == typeof(string))
closure((T)(object)webRequest.text);
else if(typeof(T) == typeof(MovieTexture))
closure((T)(object)webRequest.movie);
else if(typeof(T) == typeof(byte[]))
closure((T)(object)webRequest.bytes);
else
throw new System.NotSupportedException("Could not interpret response data as " + typeof(T).Name + ". Supported types include Texture, MovieTexture, byte[] and string.");
}
}
A cleaner option might be to supply a function to perform the property selection:
private IEnumerator _HandleResult<T> (System.Action<T> closure, Func<WebRequest, T> selector, System.Action<string> onError){
yield return webRequest;
if (SuccessWithoutErrors(onError)) {
closure(selector(webRequest));
}
}
Then you could have a function signature and call site like the following:
void DoSomethingWithTexture(Texture t) {}
_HandleResult<Texture>(DoSomethingWithTexture, wr => wr.Texture, onError);
This second approach is cleaner and more flexible (what if you later want to add a Texture2
property to the object you're processing?) but requires an API change and may be more difficult to implement into existing code.
Try this:
private IEnumerator _HandleResult<T>(object closure, System.Action<string> onError)
{
yield return webRequest;
// Can't do a switch statement on Type, needs to be if/else chain :(
if (true)
{
if (typeof(T) == typeof(Texture))
((System.Action<Texture>)closure)(webRequest.texture);
else if (typeof(T) == typeof(string))
((System.Action<string>)closure)(webRequest.text);
else if (typeof(T) == typeof(MovieTexture))
((System.Action<MovieTexture>)closure)(webRequest.movie);
else if (typeof(T) == typeof(byte[]))
((System.Action<byte[]>)closure)(webRequest.bytes);
else
throw new System.NotSupportedException("Could not interpret response data as " + typeof(T).Name + ". Supported types include Texture, MovieTexture, byte[] and string.");
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.