Eu tenho uma DLL C ++ de terceiros que chamo de C #.
Os métodos são estáticos.
Quero abstrair isso para fazer alguns testes de unidade, então criei uma interface com os métodos estáticos, mas agora meus erros de programa com:
O modificador 'estático' não é válido para este item
MyMethod cannot be accessed with an instance reference; qualify it with a type name instead
Como posso conseguir essa abstração?
Meu código se parece com este
private IInterfaceWithStaticMethods MyInterface;
public MyClass(IInterfaceWithStaticMethods myInterface)
{
this.MyInterface = myInterface;
}
public void MyMethod()
{
MyInterface.StaticMethod();
}
Respostas:
Você não pode definir membros estáticos em uma interface em C #. Uma interface é um contrato para instâncias .
Eu recomendaria criar a interface como você está atualmente, mas sem a palavra-chave estática. Em seguida, crie uma classe
StaticIInterface
que implemente a interface e chame os métodos C ++ estáticos. Para fazer o teste de unidade, crie outra classeFakeIInterface
, que também implemente a interface, mas faça o que você precisa para lidar com seus testes de unidade.Depois de definir essas 2 classes, você pode criar a que precisa para o seu ambiente e passá-la para
MyClass
o construtor de.fonte
An interface is a contract, not an implementation.
- isso é verdade, mas completamente irrelevante ( non sequitur ) aqui, uma vez que o método estático não faz parte da implementação em si - a implementação, por definição, é baseada em dados , que são, por sua vez, inacessíveis para membros estáticos.An interface type definition can define and implement static methods (see §8.4.3) since static methods are associated with the interface type itself rather than with any value of the type.
- tenha em mente que osstatic
membros são geralmente métodos utilitários .An interface is a contract, not an implementation
é inútil, às vezes um pouco de contextualização ajuda muito. E eu concordo totalmente comstatic method is not a part of implementation itself
, métodos estáticos têm uma implementação, eles se tornam parte da implementação somente se usados como implementação na implementação de outro método. Porém meu dicionário é baseado no que aprendi, pelo que eu sei, a terminologia realmente varia dependendo também da linguagem de programação. Os métodos estáticos não podem ser interfaces porque, de qualquer forma, pode haver apenas 1 implementação.IPerson
contrato que estabelece queGetCountry
fornecerá o nome do país de origem da pessoa ... asFrenchPerson
entidades dirão "França" eGermanPerson
todas dirão "Alemanha", também útil quando diferentes tipos de entidades compartilham a mesma Tabela (Dados), como MS Azure um, dizemConnection
,Post
eComment
são armazenados naUsers
AzureTable, então entidades de árvores têm uma informação compartilhada,IUsers
poderia terGetTableName
método estático ...As interfaces não podem ter membros estáticos e os métodos estáticos não podem ser usados como implementação de métodos de interface.
O que você pode fazer é usar uma implementação de interface explícita:
public interface IMyInterface { void MyMethod(); } public class MyClass : IMyInterface { static void MyMethod() { } void IMyInterface.MyMethod() { MyClass.MyMethod(); } }
Como alternativa, você pode simplesmente usar métodos não estáticos, mesmo que eles não acessem nenhum membro específico da instância.
fonte
Você pode definir métodos estáticos em c # 8, mas deve declarar um corpo padrão para ele.
public interface IMyInterface { static string GetHello() => "Default Hello from interface" ; static void WriteWorld() => Console.WriteLine("Writing World from interface"); }
ou se você não quiser ter nenhum corpo padrão, basta lançar uma exceção:
public interface IMyInterface { static string GetHello() => throw new NotImplementedException() ; static void WriteWorld() => throw new NotImplementedException(); }
fonte
Membros estáticos são perfeitamente legais no CLR, mas não no C #.
Você poderia implementar alguma cola em IL para vincular os detalhes de implementação.
Não tem certeza se o compilador C # permitiria chamá-los?
Consulte: 8.9.4 Definição do tipo de interface ECMA-335.
fonte
CLS Rule 19: CLS-compliant interfaces shall not define static methods, nor shall they define fields.
ele continua dizendo que não há problema em consumidores compatíveis com CLS rejeitarem esses tipos de interfaces. Tentei há cerca de um ano chamar um método estático em uma interface e o compilador C # não o compilou.Common Language Specification (CLS) is a set of basic language features that .Net Languages needed.... When there is a situation to communicate Objects written in different .Net Complaint languages , those objects must expose the features that are common to all the languages.
Faz sentido que se o CLS é sobre interoperabilidade entre diferentes linguagens .NET e o C # não permite membros estáticos em uma interface, então o CLS os proibiria também, para garantir bibliotecas em outras linguagens .NET podem ser chamadas de C #.Você pode invocá-lo com reflexão:
MyInterface.GetType().InvokeMember("StaticMethod", BindingFlags.Static | BindingFlags.Public | BindingFlags.InvokeMethod, null, null, null);
fonte
OC # "Ten" vai permitir membros estáticos nas interfaces , junto com as funções. É um grande avanço, pois permitirá sobrecarregar operadores genéricos também, sem qualquer uso de reflexão. Aqui está um trecho de exemplo de como isso funciona, usando o exemplo clássico de monóide, que é apenas um jargão para dizer "algo que pode ser adicionado". Retirado diretamente de Mads Torgersen: C # into the Future :
interface IMonoid<T> { static T Zero { get; } static T operator +(T t1, T t2); } public static T AddAll<T>(T[] ts) where T : IMonoid<T> { T result = T.Zero; foreach (T t in ts) { result += t; } return result; } role IntAddMonoid extends int : IMonoid<int> { public static int Zero => 0; } IntAddMonoid[] values = new int[] {1, 2, 4, 8, 16, 32}; int sixtyThree = AddAll<IntAddMonoid>(values); // == 63
Recursos adicionais:
Jeremy Bytes: membros estáticos da interface C # 8
EDITAR
Este post originalmente afirmava que os membros estáticos da interface seriam adicionados em C # 8.0 , o que não é verdade, interpretei mal as palavras de Mads Torgersen no vídeo. O guia oficial do C # 8.0 ainda não fala sobre membros da interface estática, mas está claro que eles estão trabalhando nisso há muito tempo.
fonte
Por que você não pode ter um método estático em uma interface: Por que o C # não permite que métodos estáticos implementem uma interface?
No entanto, eu sugeriria remover os métodos estáticos em favor dos métodos de instância. Se isso não for possível, você pode envolver as chamadas de método estático dentro de um método de instância e, em seguida, criar uma interface para isso e executar seus testes de unidade a partir dela.
ie
public static class MyStaticClass { public static void MyStaticMethod() {...} } public interface IStaticWrapper { void MyMethod(); } public class MyClass : IStaticWrapper { public void MyMethod() { MyStaticClass.MyStaticMethod(); } }
fonte
C # 8 permite membros estáticos nas interfaces
interface (referência C #)
Por exemplo
public interface IGetSomething { public static string Something = "something"; } var something = IGetSomething.Something;
fonte
Não vejo problemas além do compilador pensar que eu não deveria fazer isso. C # não pode herdar de mais de uma classe base, que chatice quando você está acostumado a fazer isso, frontalmente você pode fazer várias interfaces, então eu abusei disso para obter os recursos de que preciso ;-)
Você deve verificar se há null, etc., no entanto, aqui está uma versão simplificada que implementa o Parse para obter uma classe de um serviço da web ou banco de dados
/// <summary> /// Implements parse /// </summary> /// <typeparam name="T">the type to parse</typeparam> public interface IParse<T> { /// <summary> /// implements parse from string to type /// </summary> /// <param name="text">value to parse</param> /// <returns></returns> static T Parse(string text)=>JsonConvert.DeserializeObject<T>(text, settings:new JsonSerializerSettings() { ConstructorHandling= ConstructorHandling.AllowNonPublicDefaultConstructor }); /// <summary> /// implements parse from string to type /// </summary> /// <param name="text">value to parse</param> /// <param name="settings">the settings to us</param> /// <returns></returns> static T Parse(string text, JsonSerializerSettings settings) =>JsonConvert.DeserializeObject<T>(text, settings); }
Então, apenas chamo a interface no código que possui List como o valor de retorno.
Aqui está um recorte em que li JSON do banco de dados, preenchendo-o para um tipo que tem Json implementado
//some plugging code using (var reader = cmd.ExecuteReader(behavior: CommandBehavior.CloseConnection | CommandBehavior.SingleResult)) { if (reader.HasRows) { while (reader.Read()) { rows++; try { var json = reader.GetString(0); result.Add(IParse<T>.Parse(json)); } catch { failed++; } } } } //other plugging code
Com> ver versão 8 você tem a implementação padrão, então "a caixa de Pandora está aberta"
fonte