C
C#3mo ago
Kaihyo

Creating a delegate that accept a ref from a struct method

Hi ! I am working within Unity but this is a C# question. I am trying to implement attributes that alter the appearance of fields in the inspector depending on a condition passed as string. The condition may be a field, a property or a method, which MemberInfo is fetched through reflection. My previous was working in most scenarios except for the case where the attribute is applied on struct's member (which makes sense since struct are not supposed to be mutable). Since my end users may do some shenanigans with struct, I searched a solution and found this post : https://stackoverflow.com/a/1212396 So I tried to adapt it to my needs but I get this error :
ArgumentException: method arguments are incompatible
System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, System.Boolean throwOnBindFailure, System.Boolean allowClosed) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
ArgumentException: method arguments are incompatible
System.Delegate.CreateDelegate (System.Type type, System.Object firstArgument, System.Reflection.MethodInfo method, System.Boolean throwOnBindFailure, System.Boolean allowClosed) (at <321eb2db7c6d43ea8fc39b54eaca3452>:0)
Since the post is pretty old, my question is: is the answer from the post still valid ? Here is my implementation :
private delegate TResult RefFunc<TArg, TResult>(ref TArg arg);

private static bool TryGetDelegate<T>(string memberName, out RefFunc<T, bool> @delegate)
{
System.Type typeOfT = typeof(T);
MethodInfo method = typeOfT.GetMethod(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new System.Type[] { }, null);
if (method == null)
{
@delegate = null;
return false;
}

@delegate = (RefFunc<T, bool>)System.Delegate.CreateDelegate(typeof(RefFunc<T, bool>), null, method); // The error occures here
return true;
}
private delegate TResult RefFunc<TArg, TResult>(ref TArg arg);

private static bool TryGetDelegate<T>(string memberName, out RefFunc<T, bool> @delegate)
{
System.Type typeOfT = typeof(T);
MethodInfo method = typeOfT.GetMethod(memberName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, new System.Type[] { }, null);
if (method == null)
{
@delegate = null;
return false;
}

@delegate = (RefFunc<T, bool>)System.Delegate.CreateDelegate(typeof(RefFunc<T, bool>), null, method); // The error occures here
return true;
}
And the current attribute setup:
public class TestClass : UnityEngine.MonoBehaviour
{
[ShowIf(nameof(ShowIf))]
public UnityEngine.Object TestUnityObject;

private bool ShowIf()
{
return this.ShowGroup;
}
}
public class TestClass : UnityEngine.MonoBehaviour
{
[ShowIf(nameof(ShowIf))]
public UnityEngine.Object TestUnityObject;

private bool ShowIf()
{
return this.ShowGroup;
}
}
8 Replies
Cattywampus
Cattywampus3mo ago
cant you just do Action<Span<T>>? also plain c# delegates cant be serialized in unity that said pass your struct as span instead
Kaihyo
KaihyoOP3mo ago
I'm not trying to serialize the delegate. It just creates a schedule in the inspector that will call the getter (ShowIf in the example) and then invoke a callback using the output.
Cattywampus
Cattywampus3mo ago
hmmm.. seems like you're avoiding custom editor here, right?
Kaihyo
KaihyoOP3mo ago
Yes. It's for people who want quick formatting without inspector code or Odin.
Cattywampus
Cattywampus3mo ago
sorry for ruining the party, but it's almost impossible custom editor is the way to do it you can abuse their persistent listeners/events for it yeah, so anything inspector related, they need to be able to be serialized... thus they've their own native wappers for it
Kaihyo
KaihyoOP3mo ago
Yeah, for struct using a PropertyDrawer that relies on SerializedObject would make more sense (it would make even more sense for people to stop trying to listen for changed made on a struct). The rest is fine, I got most of the drawing/data update working, but struct are a PIA for some use cases haha "It's nearly impossible/very complicated to do" is an OK answer. I needed argument to discuss it with my team
Cattywampus
Cattywampus3mo ago
yeah, this is very very easy todo with custom editor.. doesn't matter what the types are default PropertyDrawers ain't even good for general use cases
Anton
Anton3mo ago
Well, the delegate type is incorrect it might be correct for structs with the ref but not for classes but I would guess this is just not allowed at least without boxing you'll probably need to make them static and take a ref explicitly

Did you find this page helpful?