【问题标题】:Foreach generic as specific typeForeach 泛型作为特定类型
【发布时间】:2022-08-14 03:53:42
【问题描述】:

无法解决并找到解决方案。我想创建易于扩展的结构并将数据保存到 ScriptableObjects。 例如,我根据 SettingsSO 创建了 2 个 AudioSettings(资产):DefaultSettings、CurrentSettings,然后我将在 UnityEditor 上设置 Default 并存储用户的设置 在 Current 中,如果 Current == null 则 Current = CreateInstance<Default>。 所以任何设置组都有2个参考。将来我想在 SettingManager 中添加另一个设置组,并能够将它们全部添加到某个列表或字典中,然后 foreach 做一些常见的事情。例如加载默认设置。

设置管理器.cs

public class SettingsManager
{
    [SerializeField] private SettingGroup<VideoSettings> _videoSettings;
    [SerializeField] private SettingGroup<AudioSettings> _audioSettings;

    private Dictionary<Type, SettingGroup> _settingDictionary;

    public void Init()
    {
        _settingDictionary = new Dictionary<Type, SettingGroup>
        {
            { _audioSettings.GetType(), _audioSettings },
            { _videoSettings.GetType(), _videoSettings }
        };
    }

    private void LoadDefaultSetting()
    {
        foreach (var pair in _settingDictionary)
        {
            //var eachSettingGroup = (pair.Key)pair.Value;              //Error Cannot resolve symbol \'pair\'
            //var eachSettingGroup = pair.Value as pair.Key;            //Error Cannot resolve symbol \'pair\'
            //var eachSettingGroup = (typeof(pair.Key))pair.Value;    //Error Cannot resolve symbol \'pair\'
            var eachSettingGroup = I need settings.Default HelpMeGuys!! (;
            eachSettingGroup.Init();
        }
    }
}

设置组.cs

public class SettingGroup<T> : SettingGroup where T : SettingsSO
    {
        public T Default => _default;
        public T Current => _current;
        public Type SettingsType => typeof(T);


        [SerializeField] private T _default;
        [SerializeField] private T _current;
        private T _lastSaved;

        public void Init()
        {
            if (_current == null)
            {
                Debug.LogWarning(\"Current settings reference not found. Default settings using instead without saving.\");
                _current = ScriptableObject.CreateInstance<T>();
                _default.CopyDataTo(_current);
            }

            _lastSaved = ScriptableObject.CreateInstance<T>();
            _current.CopyDataTo(_lastSaved);
        }
    }

音频设置.cs

public class AudioSettings : SettingsSO
{
   public bool MusicEnabled;
   public bool SoundEnabled;
   public float MusicVolume;
   public float SoundVolume;
}

设置SO.cs

public abstract class SettingsSO : ScriptableObject
{
    public string Description;
}
  • SettingGroup 中似乎没有 Default,对于实际的类型转换,您需要在编译时定义类型,它不能是运行时值。您可能会尝试使用反射来做一些事情,尽管我不确定 Unity 是否支持所有平台上的反射
  • 你只是想迭代你的字典却不知道怎么做?
  • 至于我,您可以在 SettingsSO 方法中创建,命名为 \"GetDefaultSetting\" 并在音频和视频设置中覆盖此方法

标签: c# unity3d generics scriptable-object


【解决方案1】:

有点不清楚您的SettingGroup&lt;T&gt; 需要哪些功能,以及SettingGroup 中是否有任何重要的东西,我们看不到。但是您可以通过引入带有covariant generic type 的接口来解决眼前的问题:

// Notice the 'out' keyword    vvv
public interface ISettingGroup<out T> where T : SettingsSO
{
    public T Default { get; }
    public T Current { get; }
    public Type SettingsType { get; }
    
    public void Init();
}

然后在您的SettingGroup 中实现该接口:

public class SettingGroup<T> : ISettingGroup<T> where T : SettingsSO
{ /* ... */ }

在您的SettingsManager 中,我们现在可以更改字典值的类型:

public class SettingsManager
{
    [SerializeField] private SettingGroup<VideoSettings> _videoSettings;
    [SerializeField] private SettingGroup<AudioSettings> _audioSettings;

    // Now uses the interface vvvvvvvvvvvvvvvvvvvvvvv
    private Dictionary<Type,  ISettingGroup<SettingsSO>> _settingDictionary;

    public void Init()
    {
        _settingDictionary = new Dictionary<Type, SettingGroup>
        {
            { _audioSettings.GetType(), _audioSettings },
            { _videoSettings.GetType(), _videoSettings }
        };
    }

    private void LoadDefaultSetting()
    {
        foreach (var pair in _settingDictionary)
        {
            // No need for any type casting now...
            var settingGroup = pair.Value;
            var settingsDefault = settingGroup.Default;
            settingGroup.Init();
        }
    }
}

【讨论】:

    【解决方案2】:

    我找到了解决方案,我忘记了那些设置组将使用相同的方法,我可以将这些方法替换为接口。 而且我不需要知道这是设置组的哪种类型。

    设置组.cs

        public interface SettingGroup
        {
            void Init();
        }
    
        [Serializable]
        public class SettingGroup<T> : SettingGroup where T : SettingsSO
        {
            [SerializeField] private T _default;
            [SerializeField] private T _saved;
            [SerializeField] private T _current;
    
            public T CurrentSettings  => _current;
    
            public void Init()
            {
                if (_saved == null)
                {
                    Debug.LogWarning(
                        "Current settings reference not found. Default settings using instead without saving.");
                    _saved = ScriptableObject.CreateInstance<T>();
                    _saved.CopyDataFrom(_default);
                }
    
                _current = ScriptableObject.CreateInstance<T>();
                _current.CopyDataFrom(_saved);
            }
        }
    }
    

    设置管理器.cs

        [Serializable]
        public class SettingsManager
        {
            [SerializeField] private SettingGroup<VideoSettings> _videoSettings;
            [SerializeField] private SettingGroup<AudioSettings> _audioSettings;
    
            public VideoSettings Video => _videoSettings.CurrentSettings;
            public AudioSettings Audio => _audioSettings.CurrentSettings;
    
            private List<SettingGroup> _settingList;
    
            public void Init()
            {
                //TODO don't forget to add all above SettingsGroups to list 
                _settingList = new List<SettingGroup>
                {
                    _audioSettings, 
                    _videoSettings
                };
    
                foreach (var settingGroup in _settingList)
                {
                    settingGroup.Init();
                }
            }
       }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-06-03
      • 2021-05-19
      • 2021-12-06
      • 2020-11-11
      • 2015-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多