I have a concrete class implementation of an interface that has a method declaration like so....
public interface IControllerContent
{
IEnumerable<KeyValuePair<string, string>> LocalResource();
}
public class BaseControllerContent : IControllerContent
{
public IEnumerable<KeyValuePair<string, string>> LocalResource()
{
ResourceSet resourceSet =
ResourceManager.GetResourceSet(new CultureInfo(this.Tenant.Locale), true, false);
IDictionaryEnumerator dictionaryEnumerator = resourceSet.GetEnumerator();
while (dictionaryEnumerator.MoveNext())
{
//only string resources
var value = dictionaryEnumerator.Value as string;
if (value != null)
{
var key = (string)dictionaryEnumerator.Key;
yield return new KeyValuePair<string, string>(key, value);
}
}
}
}
All fairly straight forward. Declare an interface and implement from a concrete class. However when I try to call the LocalResource method of the concrete class I get an exception.
public T Build<T>() where T : class, IControllerContent
{
var controllerContent = Activator.CreateInstance(typeof(T)) as T;
try
{
**controllerContent.CDict = (Dictionary<string, string>) controllerContent.LocalResource();**
controllerContent.CDict = (Dictionary<string, string>) JsonReader<T>.Parse(this.Content);
return controllerContent;
}
catch (Exception ex)
{
throw new Exception();
}
}
The exception occurs when trying to execute the LocalResource() method (highlighted above).
{System.InvalidCastException: Unable to cast object of type '<LocalResource>d__0' to type 'System.Collections.Generic.Dictionary`2[System.String,System.String]'. at FantasyLeague.Web.Mvc.ControllerContentBuilder.BuildT in C:\Users\andrew.knightley\git\FAST\src\ContentManagement\FantasyLeague.Web.Mvc\ControllerBase.cs:line 290}
Basically it appears that C# is trying to parse the interface method signature as a Dictionary, hence the error, however surely it should be trying to execute the concrete implementation. Anyone know whats going on here? I've tried casting to interface and concrete type and all combinations, it still isn't having it. I have reread all the MSDN stuff on interfaces, according to their articles there is nothing out of the ordinary here.
Many thanks in advance.
Simply put, your implementation isn't returning a Dictionary<string, string>
, so you can't cast to it. You're just returning a sequence of key/value pairs - that's not the same thing as a dictionary.
Note that this has nothing to do with the method being declared on an interface - you're calling the right implementation, but just casting the result. You can see this by separating the two:
IEnumerable<KeyValuePair<string, string>> tmp = controllerContent.LocalResource();
controllerContent.CDict = (Dictionary<string, string>) tmp; // Bang!
The simplest fix would be to create a dictionary with LINQ:
controllerContent.CDict = controllerContent.LocalResource()
.ToDictionary(x => x.Key, x => x.Value);
Note that an alternative implementation of your LocalResource()
method could also use LINQ:
public IEnumerable<KeyValuePair<string, string>> LocalResource()
{
ResourceSet resourceSet = ResourceManager.GetResourceSet(
new CultureInfo(this.Tenant.Locale), true, false);
return resourceSet.Cast<DictionaryEntry>()
.Where(de => de.Value is string)
.Select(de => new KeyValuePair((string) de.Key,
(string) de.Value));
}
That will end up boxing each DictionaryEntry
, but it's somewhat simpler than your iterator block approach, IMO.
See more on this question at Stackoverflow