我知道这个理论,它们很棒,框架中包含的内容可以简化许多事情,甚至可以提高性能。
关于这个主题的答案有很多非常好的例子,但对我来说通常具有较低的实用价值或者框架中已经存在的例子。
问题是,在哪种情况下你决定写一个你自己的使用泛型的类?
答案 0 :(得分:3)
每当类在尚未定义的类型上执行一组操作时,我都会使用泛型。
例如,假设您实现了一组数学运算,但希望您的类的用户能够确定实际的数字类型(int
,short
,...) 。通过不指定类型(通过使其成为通用),可以更广泛地使用泛型类。
另一个相关的好处是,为泛型类生成的代码实际上将更具体,使用例如。较少的演员操作和可能较少的运行时测试。 .NET框架中的通用容器就是一个很好的例子。
答案 1 :(得分:3)
每次我需要在不同类型的对象上应用相同的算法/相同逻辑时,我都在使用泛型。
示例是通用存储库:
public interface IRepository<T> where T : class, IEntity
{
IQueryable<T> GetQuery();
void Update(T entity);
void Insert(T entity);
void Delete(int id);
}
public interface IEntity
{
int Id { get; set; }
}
答案 2 :(得分:1)
哇 - 太多的例子(可能太快涉及快速的答案......)我可以给。
我在许多地方使用泛型(特别是要包含适用于许多场景的常见模式)。但是,我提出的最有益的用途之一是加速基于反射或其他动态代码,这些代码将根据操作数的类型而改变,同时将其隐藏起来。
所以,例如(一个虚构的因为我的真实世界的例子太过涉及和抽象而没有很多背景),让我说我有一个组件,它使用字符串几乎完全从对象中检索数据值。当然,如果它做了一两次然后没有问题,保持反射,但如果它做了很多,那么你想要做的是编译可以更快地检索值的动态委托。所以,
public static class NamedValueAccessor<T>
{
private Dictionary<string, Func<T, object>> _accessors;
private Dictionary<string, Action<T, object>> _writers;
public object GetValue(T instance, string name) { }
public void SetValue(T instance, string name, object newValue) { }
}
GetValue
和SetValue
可以反映其属性的T
类型,检查CanRead
的{{1}}和CanWrite
值。一旦确认一切正常,他们就可以使用System.Linq.Expressions动态构建一个读/写委托(简单,因为所有的反射信息都可用)并将其缓存在字典中。
哦是的 - 在我的初稿中忘了 - 注意PropertyInfo
代表只能用.Net 4.0中的表达式编译,除非你手动编写IL。
以此为基础,您可以在其他泛型中使用此类,可能是扩展方法:
SetValue
其中,因为它没有约束可以适用于所有类型。
并且通过反思,如果您拥有的只是一个public static GetPropertyValue<T>(this T instance, string name)
{
return NamedValueAccessor<T>.GetValue(instance, name);
}
- 您可以使用它的object
方法来获取运行时类型,执行GetType()
。但是,遵循相同的模式,在这种情况下,您最好为每个typeof(NamedValueAccessor).MakeGenericType(o.GetType()).GetMethod(...).Invoke(...)
构建一个代理的动态缓存,这些缓存是通过传入类型的正确Type
方法实现的。
<强>更新强>
因此,为了解释通用在这个例子中为我们做了什么:
1)如果在编译时已知泛型类型参数(即NamedValueAccessor<T>.GetValue
),则编译器将解析基于类型的属性高速缓存,并编译为泛型的特定实例。在运行时仍需要做的就是在字典中查找委托并执行它。
2)单独类型的缓存保持分开
3)可以在静态类的静态构造函数中对缓存进行初始化,并对类型进行简单反射,以获取所有支持的属性并预编译所有委托。当然,你必须小心这段代码,以确保它不会引发运行时错误 - 没有人喜欢NamedValueAccessor<MyType>.GetValue("Foo")
。如果你这样做,那么你也不必担心多线程环境 - 缓存是不可变的。
在第3点 - 如果类型是IDynamicObject,那么当然这个策略失败了 - 但你可以委托给实例的动态接口。
END UPDATE
实际上,我使用它是为了做更复杂的事情,而不仅仅是包装属性设置器和getter(ComponentModel命名空间中的代码可能更好 - 就像Mvc利用它的方式一样),但正确编织这些各种解决方案为最终用户(在我的情况下为应用程序编码器)提供了出色的性能和可访问性。
我也希望这个答案过于抽象,无法获得任何选票,但无论如何我都会把它扔出去,因为我们不提供获得投票的答案 - 而是告知提出问题的人:)
答案 3 :(得分:1)
我使用泛型为实现几个接口的对象添加扩展方法,所以
public static MyExtension<T>(this T myobject) where T : ISomeInterface, ISomeOtherInterface
{
//Do some stuff on myObject
}