我有一个界面ISomeThing:
public interface ISomeThing {}
Run Code Online (Sandbox Code Playgroud)
和实现它的2种类型:
public class SomeThing1 : ISomeThing {}
public class SomeThing2 : ISomeThing {}
Run Code Online (Sandbox Code Playgroud)
然后我有一个使用这些类型的类型:
public class FooBar
{
public ICollection<SomeThing1> Foo { get; set; }
public ICollection<SomeThing2> Bar { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
然后我必须使用反射来访问以下属性FooBar:
var properties = typeof(FooBar).GetProperties()
.Where(p => typeof(ICollection<>).IsAssignableFrom(p.PropertyType));
Console.WriteLine(properties.Count());
Run Code Online (Sandbox Code Playgroud)
输出将是0.即使我更改代码以查找ICollection<ISomeThing>它也行不通:
var properties = typeof(FooBar).GetProperties()
.Where(p => typeof(ICollection<ISomeThing>).IsAssignableFrom(p.PropertyType));
Console.WriteLine(properties.Count());
Run Code Online (Sandbox Code Playgroud)
我想直接获得进入酒店,因为ICollection在带来Remove等等.所以,我需要演员来ICollection<T>.
编辑
我改变了我的样本ISomeThing而不是DateTime.关键是我在运行时不知道确切的泛型类型,但我需要得到一个ICollection<ISomeThing>结果.
**编辑2**
现在我终于想出了我的榜样.这个例子说明了为什么我需要这么糟糕的演员表.
var properties = instance.GetType().GetProperties();
foreach (var property in properties){
var value = property.GetValue(instance);
if (value is ISomeThing someThingValue && someThingValue.IsSomeCondition)
{
// Do a ISomeThing-specific thing here
}
else if (property.PropertyType.GetInterfaces().Concat(new []{property.PropertyType})
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ICollection<>)
&& typeof(ISomeThing).IsAssignableFrom(i.GetGenericArguments().Single())))
{
var someThingValues = value as ICollection<ISomeThing>; // <-- this results in null
foreach (var someThingInstance in someThingValues)
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
// Enter recursion for possible nested ISomeThings
}
Run Code Online (Sandbox Code Playgroud)
ICollection<DateTime> collection = new HashSet<ISomeThing>();
Run Code Online (Sandbox Code Playgroud)
这是没有意义的.我猜你打算输入
ICollection<ISomeThing> collection = new HashSet<ISomeThing>();
Run Code Online (Sandbox Code Playgroud)
继续.
Console.WriteLine(collection.GetType() as ICollection<ISomeThing>);
Run Code Online (Sandbox Code Playgroud)
这是null因为collection.GetType()返回a Type,而a Type没有实现ICollection<ISomething>.
Console.WriteLine(typeof(ICollection<>)
.IsAssignableFrom(collection.GetType()));
Run Code Online (Sandbox Code Playgroud)
这是错误的,因为IsAssignableFrom意味着"可以为类型的变量ICollection<>赋予类型的值HashSet<ISomething>.没有ICollection<>类型的变量.在它们可以是变量的类型之前必须构造泛型类型.
当我看第1行和第3行时,我觉得输出对我来说几乎就是这样
它不是.
但我想直接获得进入酒店,因为
ICollection在带来Remove等等.所以,我需要演员来ICollection<T>.
我不能为我的生活弄清楚这句话的意思.你能澄清一下吗?
更新:
根据问题的更新,我现在怀疑实际问题是
给定a
Type,我想知道有多少属性类型ICollection<T>在哪里T实现ISomeThing"
十分简单:
Type type = typeof(FooBar);
var properties = type
.GetProperties()
.Where(p => p.PropertyType.IsGenericType)
.Where(p => p.PropertyType.GetGenericTypeDefinition() == typeof(ICollection<>))
.Where(p => typeof(ISomeThing).IsAssignableFrom(
p.PropertyType.GenericTypeArguments.Single()))
Console.WriteLine(properties.Count()); // 2
Run Code Online (Sandbox Code Playgroud)
或许它是
给定a
Type,我想知道有多少属性可以实现ICollection<T>在哪里T实现ISomeThing"
那就是
var properties = type
.GetProperties()
.Where(p => p.PropertyType
.GetInterfaces()
.Concat(new [] {p.PropertyType})
.Where(i => i.IsGenericType)
.Where(i => i.GetGenericTypeDefinition() == typeof(ICollection<>))
.Where(i => typeof(ISomeThing)
.IsAssignableFrom(i.GetGenericArguments().Single()))
.Any());
Run Code Online (Sandbox Code Playgroud)
更新:根据这个令人困惑的问题的最新更新,现在的问题是如何重写这个循环,使其工作:
{
var someThingValues = value as ICollection<ISomeThing>; // <-- this results in null
foreach (var someThingInstance in someThingValues)
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
Run Code Online (Sandbox Code Playgroud)
这很简单.您只是不尝试强制转换,ICollection<anything>因为您的示例中不需要该类型的任何成员.我们知道什么?该类型是ICollection<T>哪里T的ISomeThing.这是一个必要条件,这种类型实现非通用IEnumerable和通用IEnumerable<T>.
这是不是该要求IEnumerable只实现产量的对象ISomeThing,但对象的作者将是疯狂的有IEnumerable产量不同的对象比可能是集合中,让我们保持谨慎,在那里坚持一个类型的过滤器.
var properties = instance.GetType().GetProperties();
foreach (var property in properties){
// Let's emphasize here that we don't know the type by using
// object instead of var
object value = property.GetValue(instance);
// We need to bail if this is null.
if (value == null)
continue;
if (value is ISomeThing someThingValue && someThingValue.IsSomeCondition)
{
// Do a ISomeThing-specific thing here
}
else if (property.PropertyType.GetInterfaces().Concat(new []{property.PropertyType})
.Any(i => i.IsGenericType
&& i.GetGenericTypeDefinition() == typeof(ICollection<>)
&& typeof(ISomeThing).IsAssignableFrom(i.GetGenericArguments().Single())))
{
var ie = value as IEnumerable;
Debug.Assert(ie != null);
foreach (ISomeThing someThingInstance in ie.OfType<ISomeThing>())
{
if(someThingInstance.IsSomeCondition)
{
// Do the thing again
}
}
}
// Enter recursion for possible nested ISomeThings
}
Run Code Online (Sandbox Code Playgroud)
你也可以用它来收紧一点
var q = ie.OfType<ISomeThing>().
.Where(x => x.IsSomeCondition);
foreach (ISomeThing someThingInstance in q)
{
// Do the thing again
}
Run Code Online (Sandbox Code Playgroud)
奖金锻炼
现在,可以合理地注意到ICollection<T>也可以转换为IEnumerable<T>.我们可以这样说:
ICollection<T>一些T实现ISomeThing.ICollection<T>到IEnumerable<T>任何T.IEnumerable<T>对一些T实现ISomeThing.IEnumerable<T>是协变的T,因此我们可以ICollection<T>直接转换IEnumerable<ISomeThing>并枚举它.var ie = value as IEnumerable<ISomeThing>;
Debug.Assert(ie != null);
foreach (ISomeThing someThingInstance in ie)
Run Code Online (Sandbox Code Playgroud)
上述论点包含一个逻辑缺陷.你看到了吗?
给它一些思考,一旦你弄清楚为什么这个逻辑是错误的,在评论中留下答案.