The problem is that as-written, your T data
data typereference could conceivably be a local struct allocated on the stack, that's vanished from existence by the time handle.Completed
is called. Or a reference type variable that belongs to such an ephemeral struct. That could leave us with effectively a dangling pointer when the callback is ready to call, so the C# language specification makes this illegal.
You'll need to give your function something that can guarantee some independent lifecycle management, so we have a strong guarantee that the variable we're trying to set still exists as long as our callback holds a reference to it.
Here's one way you can tackle that:
public enum LoadStatus {
Loading,
Invalid,
DataReady
}
public class Loadable<T> {
public T data { get; private set; }
public LoadingStatus status { get; private set; }
public void OnComplete(AsyncOperationHandle<T> handle) {
T result = handle.Result;
if(result == Default(T)) {
status = LoadingStatus.Invalid;
return;
}
data = result;
status = LoadingStatus.DataReady;
}
}
Then you can either pass your Loadable<T>
by reference (which happens without the ref
keyword since it's a class type), or return a new Loadable<T>
from your extension method.
public static void TryLoadData<T>(this AssetReference assetref, Loadable<T> data)
{
var handle = assetref.LoadAssetAsync<T>();
handle.Completed += data.OnComplete;
}
public static Loadable<T> TryLoadData<T>(this AssetReference assetref)
{
var handle = assetref.LoadAssetAsync<T>();
var data = new Loadable<T>();
handle.Completed += data.OnComplete;
return data;
}