[英]Generic Delegate C#
我试图弄清楚如何使泛型委托返回一个通用值。 我的第一个非泛型场景看起来像这样。
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;
}
这里没问题。 一切正常。 然而,当我把它变成通用时,事情就会失去控制。
delegate T FirstDelegate<T>(T i);
static FirstDelegate<T> method; <--
他已经在这里开始抱怨找不到类型或名称空间等。 任何人都有任何关于如何使这个工作的想法?
编辑:我的真正目标是我有一个可以包含许多不同缓存对象的缓存。 现在我想要一个通用的方法,所以我可以通过这个方法得到所有对象。 我可以让它返回对象或基类,但是我仍然必须在每个对象的任何地方使用它。
狗/猫的例子非通用的部分正在工作..通用..不是那么多
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
{
}
你的事情太复杂了。
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");
}
}
但是你的整个设计有一个缺陷:它打破了Liskov替代原则 。
该LSP指出,如果T
(例如, Cat
)是的一个亚型Animal
,然后的任何实例Animal
可以被替换T
没有任何令人惊讶的效果。
让我说清楚。 假设你决定创造一种新的动物, 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();
这将永远适用于任何种类的动物。
注意:我认为Cache
不应该是静态的。 相反,您可以使用Singleton模式在应用程序中创建一个缓存实例(每种动物类型),或使用依赖注入(使用Castle Windsor等框架)将缓存注入每个客户端。
您可以在声明时将方法的泛型类型参数绑定到特定类型(如提到的@Sean),也可以将封闭类型设置为泛型。
public class MyClass<T>
{
public FirstDelegate<T> Method(){...}
}
您也可以保留T
unbound(不使封闭类型通用),但您必须在方法名称后声明T
,如下所示:
public FirstDelegate<T> Method<T>(){...}
无论哪种方式,在某个时间点, T
将绑定到特定类型。 在这种情况下,当您创建MyClass
的实例(即, new MyClass<int>
)时,将绑定T
,就像使用List<T>
。
在声明method
时需要指定类型:
static FirstDelegate<int> method;
如果您有一个对象实例想要获取默认值,可以使用:
public static T GetDefault<T>(T par)
{
return default(T);
}
例如:
System.Drawing.Point p = new Point();
System.Drawing.Point defaultPoint = GetDefault(p);
我的真正目标是我有一个可以包含许多不同缓存对象的缓存。 现在我想要一个通用的方法,所以我可以通过这个方法得到所有对象。 我可以让它返回对象或基类,但是我仍然必须在每个对象的任何地方使用它。
在这个特定问题中不需要使用委托,因为LINQ允许从IEnumerable
按类型选择对象:
public class AnimalCache
private readonly Animals as new HashSet(of Animal)
public function Add(Animal as Animal) as AnimalCache
Animals.Add(Animal)
return me
end function
public function GetAnimals(of AnimalType as Animal) as IEnumerable(of AnimalType)
return Animals.OfType(of AnimalType)
end function
end class
用法:
dim Cache = new AnimalCache().
Add(new Cat).Add(new Dog).Add(new Cat)
dim CachedCats = Cache.GetAnimals(of Cat)
dim CachedDogs = Cache.GetAnimals(of Dog)
请注意,如果将Giraffe
类添加到类层次结构中, AnimalCache
仍将起作用:
public class Giraffe
inherits Animal
end class
dim Cache = new AnimalCache().
Add(new Cat).Add(new Dog).Add(new Giraffe)
dim CachedGiraffes = Cache.GetAnimals(of Giraffe)
您可以在Cache类中声明Dictionary,使用Animal类类型作为键,使用List <Animal>作为值。
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main(string[] args)
{
Cache.AddCacheObj<Dog>(new Dog());
Cache.AddCacheObj<Cat>(new Cat());
var cat = Cache.GetCachedObj<Dog>();
Console.WriteLine("Cat: {0}", cat);
var dog = Cache.GetCachedObj<Cat>();
Console.WriteLine("Dog: {0}", dog);
}
}
public static class Cache
{
static Dictionary<Type, List<Animal>> dict = new Dictionary<Type, List<Animal>>();
public static T GetCachedObj<T>() where T: Animal
{
List<Animal> list;
if (dict.TryGetValue(typeof(T), out list))
{
return list.FirstOrDefault() as T;
}
return null;
}
public static void AddCacheObj<T>(T obj) where T: Animal
{
List<Animal> list;
if (!dict.TryGetValue(typeof(T), out list))
{
list = new List<Animal>();
dict[typeof(T)] = list;
}
list.Add(obj);
}
}
public class Animal
{
public override string ToString()
{
return "This is a " + this.GetType().ToString();
}
}
public class Dog : Animal
{
}
public class Cat : Animal
{
}
输出:
Cat: This is a Dog
Dog: This is a Cat
您可以在这里查看演示代码: https : //dotnetfiddle.net/FYkCw7
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.