I have multiple methods calling each other to simplify changing anything in the code and to avoid fixing errors and copy pasting. It looks like this:

Methods linking

  1. Is this a bad practice?
  2. Does it cause too much overhead from experience? (I don't have any performance problems but I try to do best in every case I can)
  3. Is this a good solution to make a private inline methods along with public ones? And call them when required?

Example Code

#if UNITY_EDITOR
public static class ScriptableObjectUtility
{
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static T CreateAssetInline<T>(string path, string tagName, T asset)
        where T : ScriptableObject
    {
        if (path == string.Empty)
            path = PathUtility.ASSETS_PATH_NAME;
        else if (!string.IsNullOrEmpty(Path.GetExtension(path)))
        {
            path = path.Replace(Path.GetFileName(AssetDatabase.GetAssetPath(Selection.activeObject)), string.Empty);
        }

        string fullGeneratedPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(path, $"[{tagName}] name.asset"));

        AssetDatabase.CreateAsset(asset, fullGeneratedPath);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
        EditorUtility.FocusProjectWindow();

        Selection.activeObject = asset;

        return asset;
    }

    public static T CreateAsset<T>(string path, string tagName, T asset)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline(path, tagName, asset);
    }
}
#endif

Final Version

This is a version where all public methods make a call to their corresponding inlined methods.

#if UNITY_EDITOR
public static class ScriptableObjectUtility
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="path"></param>
    /// <param name="tagName"></param>
    /// <param name="asset"></param>
    /// <returns></returns>
    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static T CreateAssetInline<T>(string path, string tagName, T asset)
        where T : ScriptableObject
    {
        if (path == string.Empty)
            path = PathUtility.ASSETS_PATH_NAME;
        else if (!string.IsNullOrEmpty(Path.GetExtension(path)))
        {
            path = path.Replace(Path.GetFileName(AssetDatabase.GetAssetPath(Selection.activeObject)), string.Empty);
        }

        Directory.CreateDirectory(path);

        string fullGeneratedPath = AssetDatabase.GenerateUniqueAssetPath(Path.Combine(path, $"{tagName}.asset"));

        AssetDatabase.CreateAsset(asset, fullGeneratedPath);

        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();

        EditorUtility.FocusProjectWindow();

        Selection.activeObject = asset;

        return asset;
    }

    public static T CreateAsset<T>(string path, string tagName, T asset)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline(path, tagName, asset);
    }

    /// <summary>
    /// Makes a copy of instance T and creates its asset at path.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="instance"></param>
    /// <param name="path"></param>
    /// <param name="tagName"></param>
    /// <returns></returns>
    public static T CreateAsset<T>(T instance, string path, string tagName)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(path, tagName, Object.Instantiate(instance));
    }

    // (string path, string tagName)

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static T CreateAssetInline<T>(string path, string tagName)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(path, tagName, ScriptableObject.CreateInstance<T>());
    }

    public static T CreateAsset<T>(string path, string tagName)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(path, tagName);
    }

    // (string path)

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static T CreateAssetInline<T>(string path)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(path, typeof(T).ToString());
    }

    public static T CreateAsset<T>(string path)
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(path);
    }

    // 

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private static T CreateAssetInline<T>()
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>(AssetDatabase.GetAssetPath(Selection.activeObject));
    }

    public static T CreateAsset<T>()
        where T : ScriptableObject
    {
        return ScriptableObjectUtility.CreateAssetInline<T>();
    }
}
#endif
有帮助吗?

解决方案

  1. Despite the nest chains of calls that provide default parameters, you actually only call the inlined method once. Unless you're planning on implementing the Strategy pattern, or having multile other sibling methods call it, wrapping the private method is probably not needed.
  2. Overhead in which sense? App Size? Your executable code will be noticeably larger than otherwise. Stack consumption? Probably not, unless your objects are very large (as in the range of 100's of kB each). Execute time? Again, probably not, as your stack depth isn't very large, and there aren't any loops involved at this level.
  3. The call isn't generally when to wrap a private inline method with a public method, but whether to wrap a private method with a public method. Whether a method is inlined or not is generally an optimization question (profile first!), and is usually best reserved for very small bits of code that will be called very frequently. Given that this method is making a call to a database, it's not what I would consider a good candidate for inlining. 15 lines is probably short enough, given there's only one test and no loops.
许可以下: CC-BY-SA归因
scroll top