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