C# 从泛型数组返回引用

C# 从泛型数组返回引用,c#,generics,.net-core,C#,Generics,.net Core,我有一个类,它包含组件库的列表组件子类组件库 public abstract class ComponentBase { public Type Type; public dynamic Value; public uint EntityID; } public class Component<T> : ComponentBase { public new Type Type;

我有一个类,它包含
组件库的列表<代码>组件
子类
组件库

    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;
    }

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

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

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

类基
{
公共int Id;
公共动态价值;
公共基(int-id,动态值)
{
Id=Id;
价值=价值;
}
公共重写字符串ToString()=>$“{{Id:{Id},值:{Value}”;
}
派生类:基
{
公共新int Id;
公共新价值观;
公共派生(int-id,T-value):基(id,value){}
}
静态void Main(字符串[]参数)
{
派生[]数组=新[]
{
新派生(0,“零”),
新衍生(1,“一”),
新衍生(2,“两”),
};
ref string valueRef=ref GetElement(数组,1);
valueRef=“三”;
WriteLine(string.Join(Environment.NewLine,array));
}
私有静态ref T GetElement(基[]数组,int-id)
{
//错误CS8151:返回表达式的类型必须为“T”,因为此方法通过引用返回
返回ref array.Where(x=>x.Id==Id).First().Value;
}
问题很简单,您试图返回基类字段,它的类型是
dynamic
,而不是
T

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

private static ref T GetElement(Base[]数组,int-id)
{
返回ref((派生的)array.Where(x=>x.Id==Id.First()).Value;
}
或者,在您最初的示例中:

public ref T getComponentEntity(实体),其中T:new()
{
返回ref((Component)components.Where(x=>x.EntityID==entity.Id&&x.Type==typeof(T)).First().Value;
}
现在,所有这些都表明:我敦促你们重新思考设计。可能您省略了一些初始化基本
字段的代码,这些代码与派生的
字段相同。但即使是这样(这已经够浪费的了),也没有什么可以阻止这些字段以后被不同地分配。这不仅是浪费,而且如果对象中的每个值都有两个副本,特别是当这些值不是只读的时候,这很可能会导致bug

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


此外,ref返回值应尽量少用,且仅在绝对必要时使用(例如,仅使用ref返回即可解决的关键性能问题)。当然,你的问题中缺少了上下文,所以也许你确实有一个很好的理由在这里使用该功能。但是,仅根据当前代码中的名称,我认为您可以让代码正常工作,而不会出现代码中的任何异常(成员隐藏和ref返回值)。

Wow。。。。。我实际上说不出话来。这个答案令人难以置信!为了回答您的一些问题,我使用了成员隐藏作为临时解决方案,这样我就可以将
组件
组织到一个单数类型的列表中,其中
T
有所不同<之所以使用code>ref值,是因为我需要在这些变量来源于它们来自的数组之后修改它们。我非常感谢你的回答。你没有忽视或放下我的编码方式,而是对我的问题进行了真正的破解,帮助我找到了解决方案,并向我展示了我应该如何写这篇文章。谢谢!
    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;
        }
    }