gpt4 book ai didi

c# - 从通用数组返回引用

转载 作者:行者123 更新时间:2023-12-04 15:07:13 29 4
gpt4 key购买 nike

我有一个包含 ComponentBase 列表的类. Component子类 ComponentBase .

    public abstract class ComponentBase 
{
public Type Type;
public dynamic Value;
public uint EntityID;
}

public class Component<T> : ComponentBase
{
public new Type Type;
public new T Value;
public new uint EntityID;
}

我需要一种方法来检索 refComponent<T>.ValueGetComponentOnEntity方法,我似乎无法找到它。我不太擅长泛型,所以我会把这个问题交给专业人士。

    public class ComponentDatabase
{
ComponentBase[] components;

private int componentIndex;

public T AddComponentToEntity<T>(T component, Entity entity) where T : new()
{
var x = component != null ? component : new T();
var comp = new Component<T> { EntityID = entity.Id, Type = typeof(T), Value = x };
components[componentIndex++] = comp;
return x;
}

public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First().Value;
}
}

我熬夜了,觉得有一个简单的解决办法,但我真的找不到。任何帮助将不胜感激。

最佳答案

从根本上说,您的代码存在的问题是您试图返回对错误对象成员的引用。当您实际需要类型为 T 的成员时,您将返回类型为 dynamic 的成员。

您的原始示例相当于这个更简单的示例:

class Base
{
public int Id;
public dynamic Value;

public Base(int id, dynamic value)
{
Id = id;
Value = value;
}

public override string ToString() => $"{{Id: {Id}, Value: {Value}}}";
}

class Derived<T> : Base
{
public new int Id;
public new T Value;

public Derived(int id, T value) : base(id, value) { }
}

static void Main(string[] args)
{
Derived<string>[] array = new[]
{
new Derived<string>(0, "Zero"),
new Derived<string>(1, "One"),
new Derived<string>(2, "Two"),
};

ref string valueRef = ref GetElement<string>(array, 1);

valueRef = "Three";
WriteLine(string.Join<Base>(Environment.NewLine, array));
}

private static ref T GetElement<T>(Base[] array, int id)
{
// error CS8151: The return expression must be of type 'T' because this method returns by reference
return ref array.Where(x => x.Id == id).First().Value;
}

问题很简单,您正在尝试返回基类字段,该字段的类型为 dynamic 而不是 T

要解决这个问题,您需要强制转换对象,以便从派生类型获取字段:

private static ref T GetElement<T>(Base[] array, int id)
{
return ref ((Derived<T>)array.Where(x => x.Id == id).First()).Value;
}

或者,在您的原始示例中:

public ref T GetComponentOnEntity<T>(Entity entity) where T : new()
{
return ref ((Component<T>)components.Where(x => x.EntityID == entity.Id && x.Type == typeof(T)).First()).Value;
}

现在,总而言之:我敦促您重新考虑设计。也许您省略了一些代码,这些代码将基本 Value 字段初始化为与派生 Value 字段相同的代码。但即使是这样(这已经够浪费了),也没有什么可以阻止这些字段以后被不同地分配。这不仅浪费,还可能导致错误,因为对象中的每个值都有两个副本,尤其是当这些值不是只读的时候。

应该不惜一切代价避免成员隐藏(即使用数据结构中的 new 关键字)。它只会导致困惑,并且几乎肯定会导致以后出现许多难以发现、难以修复的错误。您在这里遇到的问题只是冰山一角,但却是一个很好的例子,说明当一个对象有两个同名的不同成员时,事情会变得多么困惑。

此外,ref 返回值应该非常谨慎地使用,并且只有在绝对必要时才使用(例如,一个关键的性能问题只能使用 ref return 来解决)。当然,您的问题缺少上下文,因此您可能确实有充分的理由在此处使用该功能。但仅基于代码中存在的名称,在我看来,您可以让代码正常工作,而现在代码中没有任何奇怪的地方(成员隐藏 ref返回值)。

关于c# - 从通用数组返回引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65890050/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com