Eve*_*lie 4 c# generics delegates
我试图弄清楚如何使泛型委托返回一个通用值.我的第一个非泛型场景看起来像这样.
delegate int FirstDelegate(int i);
static FirstDelegate method;
static void Main(string[] args)
{
method = ReturnInt;
int i = method(3);
}
static int ReturnInt(int i)
{
return i;
}
Run Code Online (Sandbox Code Playgroud)
这里没问题.一切正常.然而,当我把它变成通用时,事情就会失去控制.
delegate T FirstDelegate<T>(T i);
static FirstDelegate<T> method; <--
Run Code Online (Sandbox Code Playgroud)
他已经在这里开始抱怨找不到类型或名称空间等.任何人都有任何关于如何使这个工作的想法?
编辑:我的真正目标是我有一个可以包含许多不同缓存对象的缓存.现在我想要一个通用的方法,这样我就可以通过这个方法得到所有对象.我可以让它返回对象或基类,但是我仍然必须在每个对象的任何地方使用它.
狗/猫的例子非通用的部分正在工作..通用..不是那么多
class Program
{
static void Main(string[] args)
{
//Clientside
Cache.method = GetAnimalOnClient;
//not working
Cache.methodGeneric = GetAnimalOnClientGeneric;
var cat = Cache.GetCachedObj(AnimalType.Cat);
var dog = Cache.GetCachedObj(AnimalType.Dog);
//Want do
vad dog = Cache.GetCachedObj<Dog>();
}
private static Animal GetAnimalOnClient(AnimalType type)
{
if (type == AnimalType.Dog)
return Cache._Dogs.First();
else
return Cache._Cats.First();
}
/// <summary>
/// This is the one I want to use
/// </summary>
private static T GetAnimalOnClientGeneric<T>() where T: Animal
{
if (typeof(T) == typeof(Cat))
return Cache._Cats.First() as T;
return Cache._Dogs.First() as T;
}
}
public enum AnimalType
{
Dog,
Cat
}
public static class Cache
{
delegate Animal GetCacheObjectDelegate(AnimalType type);
public static GetCacheObjectDelegate method;
delegate Animal GetCacheObjectDelegate<T>() where T : Animal;
public static GetCacheObjectDelegate<T> methodGeneric; //<--Complains here
public static List<Dog> _Dogs = new List<Dog>();
public static List<Cat> _Cats = new List<Cat>();
public static Animal GetCachedObj(AnimalType type)
{
return method(type);
}
public static T GetCachedObj<T>() where T: Animal
{
return methodGeneric<T>(); //NOPE
}
}
public class Animal
{
}
public class Dog : Animal
{
}
public class Cat : Animal
{
}
Run Code Online (Sandbox Code Playgroud)
你的事情太复杂了.
public static class Cache
{
private static List<Dog> _dogs = new List<Dog>();
private static List<Cat> _cats = new List<Cat>();
public static TAnimal GetCachedObj<TAnimal>() where T: Animal
{
if(TAnimal == typeof(Dog))
return (TAnimal) _dogs.First();
else if (TAnimal == typeof(Cat))
return (TAnimal) _cats.First();
else throw new InvalidOperationException("Invalid generic type argument");
}
}
Run Code Online (Sandbox Code Playgroud)
但是你的整个设计有一个缺陷:它打破了Liskov替代原则.
LSP声明如果T(例如Cat)是子类型Animal,则可以替换任何实例而没有任何令人惊讶的效果.AnimalT
让我说清楚.假设你决定创造一种新动物,a Giraffe.现在,如果你打电话GetCachedObj<Giraffe>,你会得到一个例外!代码中并没有对工作的任何亚型Animal,该LSP不成立!
相反,您应该使缓存类通用,并为每种动物使用缓存实例
public class Cache<T> where T: Animal
{
private static List<T> _animals = new List<T>();
public T GetCachedObj()
{
return _animals.First();
}
}
var dogsCache = new Cache<Dog>();
Dog dog = dogsCache.GetCachedObj();
var catsCache = new Cache<Cat>();
Cat cat = catsCache.GetCachedObj();
Run Code Online (Sandbox Code Playgroud)
这将永远适用于任何种类的动物.
注意:我认为Cache不应该是静态的.相反,您可以使用Singleton模式在应用程序中创建一个缓存实例(每种动物类型),或使用依赖注入(使用Castle Windsor等框架)将缓存注入每个客户端.
您可以在声明时将方法的泛型类型参数绑定到特定类型(如提到的@Sean),也可以将封闭类型设置为泛型.
public class MyClass<T>
{
public FirstDelegate<T> Method(){...}
}
Run Code Online (Sandbox Code Playgroud)
您也可以保留T未绑定(不使封闭类型通用),但您必须在方法名称T 后声明,如下所示:
public FirstDelegate<T> Method<T>(){...}
Run Code Online (Sandbox Code Playgroud)
无论哪种方式,在某个时间点,T都将绑定到特定类型.在这种情况下,T将在创建MyClass(即new MyClass<int>)的实例时绑定,就像使用a一样List<T>.