我遇到的问题是,在下面的示例中,我可以将IMyType
转换为Func<MyType<T>, bool>
,很好。但是,我无法将Func<IMyType, bool>
转换为using System;
using System.Collections.Generic;
public interface IMyType
{
string Text { get; }
int Number { get; }
}
public class MyType<T> : IMyType where T : SomeOtherType
{
public MyType()
{
Text = "Hello";
Number = 99;
}
public string Text { get; private set; }
public int Number { get; private set; }
}
public abstract class SomeOtherType
{
public int Id { get; set; }
public string Title { get; set; }
}
public class ConcreteType : SomeOtherType
{
public string Description { get; set; }
}
class Program
{
static void Main(string[] args)
{
var ok = (IMyType) new MyType<ConcreteType>();
Console.Write("I can cast MyType<T> to IMyType here");
var list = new List<Func<IMyType, bool>>();
Func<MyType<ConcreteType>, bool> func = type => false;
// list.Add(func); // Compiler error
list.Add((Func<IMyType,bool>)func); // Runtime cast error
Console.Write("Got here so ok"); // (It doesn't get here...)
}
}
。
这没有任何意义,我想知道是否有办法绕过它可能不同的架构?
我不想使用反射。
我也想了解它失败的原因。
.NET 4.5.2中的代码失败。此处的在线版本 - http://goo.gl/13z4xg - 也以同样的方式失败。
position = PositiveIntegerField(unique=True)
答案 0 :(得分:1)
抱歉......我认为各种答案很好地解释了为什么你不想这样做。即使你认为你做了(一个常见的错误,所以没有理由对此感到不好)。我没有想到,在阅读了所有这些问题及其答案之后,你不会觉得你对自己的问题有足够的答案。我不确定我能为他们增添多少,但我会尝试......
简短版本:如果您被允许将Func<MyType<ConcreteType>, bool>
的实例添加到Func<IMyType, bool>
列表中,那么其他一些代码可以将该实例作为Func<IMyType, bool>
拉出,然后尝试调用它,向代理人传递IMyType
以外的MyType<ConcreteType>
实例。
但是,您的方法(可能是给定委托声明)只需要MyType<ConcreteType>
的实例!如果它通过IMyType
的其他实现?
最好在编译时阻止代码,但是当你使用强制转换来声明你对编译器没有的类型有所了解时,这是不可能的。但是,当你试图将 如果委托引用的方法确实需要知道类型是 但是,请注意,如果确实仅在方法中使用对象的
当编译器在list.Add(func)
给出编译时错误时,编译器尝试以帮助防止您犯错误。您使用强制转换器隐藏了编译器中的错误,但这并没有改变编译器试图保存您的基本危险,因此当您尝试强制转换并在那里停止时,运行时必须介入。< / p>
IMyType
的其他实现传递给委托所代表的方法时,在演员阵容中获得运行时错误仍然会更好。
现在,你给出的代码示例并不清楚为什么你认为这甚至是有利的。所以在你的情况下,不可能知道哪种替代方案最好。MyType<ConcreteType>
,那么你就被卡住了。将代理引用该方法放在任何IMyType
可以传递给它的上下文中是不安全的。你以某种方式把自己描绘成一个角落,你需要重新考虑你的设计,因为它目前有一个根本的缺陷。IMyType
- 那么解决方案就是以这种方式声明它。例如,如果将您显示的lambda表达式转换为类型为Func<IMyType, bool>
的变量,则 可以
或者,如果您<100>确定没有代码会尝试使用除IMyType
以外的MyType<ConcreteType>
实现来调用委托,则可以包装错误委托类型在右代理类型的实例中。例如:
list.Add(o => func((MyType<ConcreteType>)o));
当然,通过这样做,您将完全删除使用通用List<T>
对象的大量类型安全功能。它绝对有“糟糕的代码味道”。但它会编译,甚至可以运行,只要你从不违反规则并尝试使用IMyType
的不同实现来调用委托。
答案 1 :(得分:0)
回答我自己的问题,或者至少是&#34;所以我怎样才能让它发挥作用&#34;一部分。
问题是差异(请参阅评论中的重复项)。在这种情况下答案是&#34;我怎样才能使它工作&#34;部分是使用List<T>.ConvertAll
(如此处所建议的 - Jon Skeet的C# variance problem: Assigning List<Derived> as List<Base>)。
对于我的需要,这个解决方案是完美的。 &#34;费用&#34;在我的情况下创建新列表并不重要 。
所以我已经完成了对示例的扩展,并使用List<T>.ConvertAll
以便非泛型感知实例可以访问这些函数。此处链接到代码 - http://goo.gl/MVnYhX - 代码也位于以下位置:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
public interface IMyType
{
string Text { get; }
int Number { get; }
}
public class MyType<T> : IMyType where T : SomeOtherType
{
public MyType()
{
Text = "Hello World";
Number = 999;
}
public string Text { get; private set; }
public int Number { get; private set; }
}
public abstract class SomeOtherType
{
public int Id { get; set; }
public string Title { get; set; }
}
public class ConcreteType : SomeOtherType
{
public string Description { get; set; }
}
public interface IFaceThatAccessesIt
{
IList<Func<IMyType, bool>> GetList();
}
public class ClassThatAccessesIt<T> : IFaceThatAccessesIt where T : SomeOtherType
{
/// <summary>
/// Generically typed inner list
/// </summary>
private readonly List<Func<MyType<T>, bool>> _innerList = new List<Func<MyType<T>, bool>>();
/// <summary>
/// Get list converted
/// </summary>
/// <returns></returns>
public IList<Func<IMyType, bool>> GetList()
{
var output = _innerList.ConvertAll(func =>
{
Func<IMyType, bool> outFunc = type => func.Invoke((MyType<T>)type);
return outFunc;
});
return output;
}
/// <summary>
/// Add to list
/// </summary>
/// <param name="func"></param>
public void AddToList(Func<MyType<T>, bool> func)
{
_innerList.Add(func);
}
}
class Program
{
static void Main(string[] args)
{
// get class / instance the uses said list
var asClass = new ClassThatAccessesIt<ConcreteType>();
var asInterface = (IFaceThatAccessesIt) asClass;
// add into list (via class, not interface)
asClass.AddToList(input => input.Number == 999);
asClass.AddToList(input => input.Text == "Hello World");
// get list from interface
var listFromInterface = asInterface.GetList();
// get function 1
var func1 = listFromInterface.First();
// invoke
var inputInstance = new MyType<ConcreteType>();
var result = func1.Invoke(inputInstance);
// print
Console.WriteLine("This result should be 'True'... {0}",result);
}
}
}
答案 2 :(得分:0)
如果不知道你所做的事情的范围越广,就无法说出你需要做什么,但我猜测的是你创造的IMyType
的每个对象。你想要添加一些函数来调用它。
如果是这种情况,那么类型安全的方式就是将它们挂钩到AddToList
,这样您就可以保留List<Func<bool>>
作为您的会员,从签名中取出MyType
完全:
public interface IFaceThatAccessesIt
{
IList<Func<bool>> GetList();
}
public class ClassThatAccessesIt<T> : IFaceThatAccessesIt where T : SomeOtherType
{
private readonly List<Func<bool>> _innerList = new List<Func<bool>>();
public IList<Func<bool>> GetList()
{
return _innerList;
}
public void AddToList(MyType<T> thing, Func<MyType<T>, bool> func)
{
_innerList.Add(() => func(thing));
}
}