Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/list/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么是「;“类型”;通用IList<;T>;?_C#_List_Generics - Fatal编程技术网

C# 什么是「;“类型”;通用IList<;T>;?

C# 什么是「;“类型”;通用IList<;T>;?,c#,list,generics,C#,List,Generics,想象一下这样的扩展 public static Blah<T>(this IList<T> ra) { .. } 这似乎奏效了。但似乎很奇怪??所以 3-事实上,最近应该是什么类型的,这样你就不必投进去了??如何使最近的与ra的类型相同?你不能这么说 private static System.Collections.Generic.IList recent; 这没有意义。“ra”到底是什么类型的?你可以简单地说,recent=ra“是”什么 (我提到这是为了U

想象一下这样的扩展

public static Blah<T>(this IList<T> ra)
 {
 ..
 }
这似乎奏效了。但似乎很奇怪??所以

3-事实上,最近应该是什么类型的,这样你就不必投进去了??如何使
最近的
ra
的类型相同?你不能这么说

private static System.Collections.Generic.IList recent;
这没有意义。“ra”到底是什么类型的?你可以简单地说,
recent=ra
“是”什么

(我提到这是为了Unity,因为您经常在Unity中使用泛型扩展。)


<P>4——如果你想有一本字典的话,就要考虑另一个困难。

private static Dictionary<object,int> recents = new Dictionary<object,int>();
等等。然而。当然,实际的随机选择感觉很糟糕;实际上,您想要的是一个相当不重复的顺序,更像是一个洗牌。通常,对任何列表或数组来说,最好的方法是将它们洗牌,并按顺序提供它们;也许每次都会重新洗牌。举个简单的例子,你有20个随机的声音效果
咆哮
,当恐龙咆哮的时候。每次你需要一个,如果你这样做的话

 roars.AnyOne();
没关系,但不太好。听起来有点糟糕。(大多数玩家会将其报告为“不是随机的”或“重复很多”。)

好多了。因此,
NextOne()
应该,单独地,(a)如果我们是在开始洗牌列表,(b)按顺序提供,(c)也许每次用完列表时都会再次洗牌。{还有更多的微妙之处,例如,在改组快结束/开始时尽量不要重复任何细节,但在这里并不重要。}

注意,子类化列表(和/或数组)会因为许多明显的原因而变得很糟糕,这是一个简单的自包含扩展的工作

private static Dictionary<object,int> nextOne = new Dictionary<object,int>();
public static T NextOne<T>(this IList<T> ra)
    {
    if ( ! nextOne.ContainsKey(ra) )
        // i.e., we've never heard about this "ra" before
        nextOne.Add(ra,0);
    
    int index = nextOne[ra];
    
    // time to shuffle?
    if (index==0)
        {
        Debug.Log("shuffling!"); // be careful to mutate, don't change the ra!
        IList<T> temp = ra.OrderBy(r => UnityEngine.Random.value).ToList();
        ra.Clear(); foreach(T t in temp) ra.Add(t);
        }
    
    T result = ra[index];
    ++index;
    index=index%ra.Count;
    nextOne[ra] = index;
    return result;
    }
那么,下面是一个使用简单的有状态扩展实现
NextOne()
的漂亮方法

private static Dictionary<object,int> nextOne = new Dictionary<object,int>();
public static T NextOne<T>(this IList<T> ra)
    {
    if ( ! nextOne.ContainsKey(ra) )
        // i.e., we've never heard about this "ra" before
        nextOne.Add(ra,0);
    
    int index = nextOne[ra];
    
    // time to shuffle?
    if (index==0)
        {
        Debug.Log("shuffling!"); // be careful to mutate, don't change the ra!
        IList<T> temp = ra.OrderBy(r => UnityEngine.Random.value).ToList();
        ra.Clear(); foreach(T t in temp) ra.Add(t);
        }
    
    T result = ra[index];
    ++index;
    index=index%ra.Count;
    nextOne[ra] = index;
    return result;
    }
private static Dictionary nextOne=new Dictionary();
公共静态T NextOne(此IList ra)
{
如果(!nextOne.ContainsKey(ra))
//也就是说,我们以前从未听说过这个“ra”
nextOne.Add(ra,0);
int index=nextOne[ra];
//该洗牌了?
如果(索引==0)
{
Debug.Log(“洗牌!”);//小心变异,不要更改ra!
IList temp=ra.OrderBy(r=>UnityEngine.Random.value).ToList();
ra.Clear();foreach(温度T)ra.Add(温度T);
}
T结果=ra[指数];
++指数;
索引=索引%ra.Count;
nextOne[ra]=指数;
返回结果;
}
这无疑是“有状态扩展”的完美例子

请注意,我只是使用了“object”


我想在某种程度上,这个QA的基本问题是,最好使用“object”这个字典,还是使用其他类型更好的字典?这就是手头的问题。干杯

最简单、类型最安全的解决方案是为每个
T
存储一个单独的值:

private static class RecentHolder<T> {
    public static IList<T> Value { get; set; }
}
public static Blah<T>(this IList<T> ra) {
    RecentHolder<T>.Value = ra;
}
私有静态类RecentHolder{
公共静态IList值{get;set;}
}
公共静态废话(此IList ra){
RecentHolder.Value=ra;
}

如果您想要一个全局最新的
IList
,其中
T
每次都可能变化,那么您唯一的选择就是使用
对象
动态
。两者都需要浇铸;后者只是自动投射

我认为您的困惑源于认为
IList
继承了
IList
-:

公共接口IList:ICollection、IEnumerable、IEnumerable
所以可以说你可以这样做,尽管我看不出有什么好处:

private static IEnumerable recent;
public static void Blah<T>(this IList<T> ra)
{
    recent = ra;
    ...
}
私有静态IEnumerable最近;
公共静态无效(此IList ra)
{
最近=ra;
...
}
通用IList的“类型”是什么

基本类型

Console.WriteLine( new List<int>().GetType().BaseType);
那你就可以

private static List<IName> recent;
public static Blah<T>(this List<IName> ra)
{
  recent = ra;
  ..
}
结果:

System.Collections.Generic.List`1[System.Int32]

一,

二,

三,

System.Collections.Generic.List`1[System.String]

乔治

亚伯拉罕

尝试:

公共静态类StatefulRandomizer
//对Intersect()使用IEquatable
其中T:i可满足
{
//这可以提高到一个百分比
//替换元素而不是硬编码
私有静态堆栈_内存=新堆栈();
私有静态IEnumerable\u缓存;
公共静态void UpdateWith(IEnumerable newCache)
{
_cache=newCache.ToList();
//再次设置堆栈,仅保留匹配的堆栈
变量匹配=_memory.Intersect(newCache);
_内存=新堆栈(匹配);
}
公共静态T getNextNonRepeatingLandom()
{
var nonrepeaters=\u缓存
。除了(_内存);
//不熟悉团结,但这会使
//感觉到我在做什么
var next=nonrepeaters.ElementAt(UnityEngine.Random(0,nonrepeaters.Count()-1));
//这么快,堆栈将知道它的计数,因此没有GetEnumerator()
//和_缓存列表相同(Count()将调用List.Count)
如果(_memory.Count>_cache.Count()/2)
{
_memory.Pop();
}
_内存推送(下一步);
下一步返回;
}
}

但是每种类型都会有一个“最新的”,而不是全球范围。而且我真的很想知道我的问题(3)的答案-嘿!这是什么鬼东西?一定有某种类型,你可以说
x=ra
(不仅仅是
对象
)@JoeBlow:不是真的。在没有单独的通用非泛型基类的情况下,
IBlah
IBlah
之间唯一的通用类型是
object
。OTOH,
IList
碰巧实现了非泛型的
IEnumerable
,因此存在这样的问题。如果它是协变的(例如,
IReadOnlyList
),那么也会有
IReadOnlyList
。类型安全,但不是线程安全。这可能是一个重要问题,具体取决于代码。(实际上适用于所有静态方法/字段..到目前为止,这里的答案并不是SLaks的答案
private static class RecentHolder<T> {
    public static IList<T> Value { get; set; }
}
public static Blah<T>(this IList<T> ra) {
    RecentHolder<T>.Value = ra;
}
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable
private static IEnumerable recent;
public static void Blah<T>(this IList<T> ra)
{
    recent = ra;
    ...
}
Console.WriteLine( new List<int>().GetType().BaseType);
Console.WriteLine( new List<int>().GetType().GetGenericTypeDefinition());
public interface IName
{
  string Name { get; set; }
}
public class Person : IName
{
  public string Name { get; set; }
}
public class Dog : IName
{
  public string Name { get; set; }
}
private static List<IName> recent;
public static Blah<T>(this List<IName> ra)
{
  recent = ra;
  ..
}
using System;
using System.Linq;
using System.Collections.Generic;                   

public class Program
{
    private static class WonkyCache
    {
        private static List<object> cache = new List<object>();
        
        public static void Add(object myItem)
        {
            cache.Add(myItem);
        }
        
        public static IEnumerable<T> Get<T>()
        {
            var result = cache.OfType<T>().ToList();
            return result;
        }
    }

    public static void Main()
    {
        WonkyCache.Add(1);
        WonkyCache.Add(2);
        WonkyCache.Add(3);
        WonkyCache.Add(Guid.NewGuid());
        WonkyCache.Add("George");
        WonkyCache.Add("Abraham");
        
        var numbers = WonkyCache.Get<int>();
        Console.WriteLine(numbers.GetType());           

        foreach(var number in numbers)
        {
            Console.WriteLine(number);
        }
        
        var strings = WonkyCache.Get<string>();
        Console.WriteLine(strings.GetType());
        
        foreach(var s in strings)
        {
            Console.WriteLine(s);
        }
    }
}
public static class StatefulRandomizer<T>
    // Use IEquatable<T> for Intersect()
    where T : IEquatable<T>
{
    // this could be enhanced to be a percentage 
    // of elements instead of hardcoded
    private static Stack<T> _memory = new Stack<T>();
    private static IEnumerable<T> _cache;

    public static void UpdateWith(IEnumerable<T> newCache)
    {
        _cache = newCache.ToList();

        // Setup the stack again, keep only ones that match
        var matching = _memory.Intersect(newCache);
        _memory = new Stack<T>(matching);
    }

    public static T GetNextNonRepeatingRandom()
    {
        var nonrepeaters = _cache
            .Except(_memory);

        // Not familar with unity.. but this should make 
        // sense what I am doing
        var next = nonrepeaters.ElementAt(UnityEngine.Random(0, nonrepeaters.Count()-1));

        // this fast, Stack will know it's count so no GetEnumerator()
        // and _cache List is the same (Count() will call List.Count)
        if (_memory.Count > _cache.Count() / 2)
        {
            _memory.Pop();
        }

        _memory.Push(next);

        return next;
    }
}